/* Katana Corp — "Atelier"
 *
 * A warm grey-green ground instead of white, panels lifted off it a little,
 * tall rows, one deep-teal accent. Nothing glares, because this gets looked
 * at all day and shown to clients.
 *
 * Single-theme on purpose: the ground colour is the identity here, and a
 * dark flip would be a different design rather than this one at night.
 */

:root{
  --bg:#E9EAE5;          /* the ground — warm grey-green, never white */
  --panel:#F7F8F4;
  --ink:#23282A;
  --mute:#6B7370;
  --faint:#8E9591;
  --line:#D8DAD3;
  --rule:#C6C9C0;
  --hover:#EDEEE8;
  --accent:#17605C;      /* deep teal, the one saturated colour */
  --accent-soft:#DCE7E4;
  --onaccent:#F7F8F4;

  /* Status is semantic, kept away from the accent so a pill never reads as
     a brand colour. Each ships with its word — never colour alone. */
  --good:#0CA30C; --warn:#B07800; --crit:#D03B3B;

  --sans:-apple-system,BlinkMacSystemFont,"Helvetica Neue","Segoe UI",Roboto,sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --r:6px;
  --gap:#FAF5DE;
  --gap-hover:#F6EFCD;
  --shadow:0 1px 2px rgba(35,40,42,.06), 0 1px 1px rgba(35,40,42,.04);
}

*{box-sizing:border-box}
/* No height:100% here. It was only ever propping up the login card, and
   combined with the zoom on <body> it broke the scroll region: the page
   went blank below the fold at anything other than 100%. */
body{
  margin:0;background:var(--bg);color:var(--ink);font-family:var(--sans);
  font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased;
}
a{color:var(--accent)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}

/* ------------------------------------------------------------- top bar */
.top{
  display:flex;align-items:center;gap:22px;height:56px;padding:0 22px;
  background:var(--panel);border-bottom:1px solid var(--line);
  position:sticky;top:0;z-index:20;
}
.brand{display:flex;align-items:center;gap:10px;font-size:15px;
       letter-spacing:-.01em;color:var(--ink);text-decoration:none}
.brand .mark{width:22px;height:22px;flex:none;color:var(--accent)}
.brand .word{font-weight:500;color:var(--mute)}
.brand .word b{font-weight:650;color:var(--ink)}
.brand:hover .word b{color:var(--accent)}
.nav{display:flex;gap:2px;margin-left:10px}
.nav a{padding:7px 12px;border-radius:var(--r);font-size:14px;
       color:var(--mute);text-decoration:none}
.nav a:hover{background:var(--hover);color:var(--ink)}
.nav a[aria-current]{color:var(--ink);background:var(--accent-soft);font-weight:550}
.top .right{margin-left:auto;display:flex;align-items:center;gap:12px;
            font-size:13.5px;color:var(--mute)}
.avatar{width:28px;height:28px;border-radius:50%;
        background:var(--accent-soft);color:var(--accent);
        border:1px solid var(--accent);
        display:grid;place-items:center;
        font-family:var(--mono);font-size:11px;font-weight:600;
        letter-spacing:.04em}
.linkbtn{appearance:none;border:0;background:none;padding:0;cursor:pointer;
         font:inherit;color:var(--mute);text-decoration:underline}
.linkbtn:hover{color:var(--ink)}

/* --------------------------------------------------------------- layout */
.wrap{padding:22px;display:flex;flex-direction:column;gap:18px}
.head{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:baseline}
.head h1{margin:0;font-size:22px;font-weight:600;letter-spacing:-.015em}
.head .sub{color:var(--mute);font-size:13.5px}
.head form{margin-left:auto;display:flex;gap:8px;align-items:center}

.flash{background:#FBE9E7;border-left:3px solid var(--crit);color:#7A2018;
       padding:10px 14px;border-radius:0 var(--r) var(--r) 0;font-size:14px}

/* ---------------------------------------------------------------- tiles */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.tile{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
      padding:14px 16px;box-shadow:var(--shadow);display:flex;
      flex-direction:column;gap:2px}
.tile .lab{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;
           text-transform:uppercase;color:var(--mute)}
.tile .val{font-size:28px;font-weight:600;line-height:1.15;letter-spacing:-.02em;
           font-variant-numeric:tabular-nums}
.tile .note{font-size:12.5px;color:var(--mute)}

/* ------------------------------------------------------------- controls */
.controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.seg{display:flex;gap:4px;flex-wrap:wrap}
.seg a{font-size:13px;padding:6px 11px;border-radius:var(--r);
       border:1px solid var(--line);background:var(--panel);
       color:var(--mute);text-decoration:none;white-space:nowrap}
.seg a:hover{color:var(--ink)}
.seg a[aria-current]{background:var(--accent);border-color:var(--accent);
                     color:var(--onaccent);font-weight:550}
.seg .count{font-family:var(--mono);font-size:11.5px;opacity:.8;margin-left:5px}
input[type=search]{
  font:inherit;font-size:13.5px;padding:6px 11px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--panel);color:var(--ink);
  min-width:210px;
}
.btn{appearance:none;font:inherit;font-size:13.5px;font-weight:550;
     padding:7px 14px;border-radius:var(--r);cursor:pointer;
     background:var(--accent);color:var(--onaccent);border:1px solid var(--accent)}
/* A link wearing .btn is a button, and buttons are not underlined. This
   was being patched a rule at a time wherever one turned up — .ownlinks,
   .thanks, .more — so each new one arrived underlined. Stated once here. */
a.btn{text-decoration:none}
.btn:hover{filter:brightness(1.08)}
.btn.quiet{background:var(--panel);color:var(--mute);border-color:var(--line)}
.btn.quiet:hover{color:var(--ink)}

/* ----------------------------------------------------------- the table */
.tablewrap{overflow-x:auto;background:var(--panel);border:1px solid var(--line);
           border-radius:var(--r);box-shadow:var(--shadow)}
table{border-collapse:collapse;width:100%;min-width:1040px;font-size:13.5px}
thead th{
  /* top:0, not the 56px height of the bar. .tablewrap has overflow-x:auto,
     which makes IT the containing block for sticky — so any offset here is
     measured from the card's own top edge, leaving a gap above the header
     and parking it on top of the first row. */
  position:sticky;top:0;z-index:5;background:var(--panel);text-align:left;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--mute);font-weight:600;
  padding:12px 14px;border-bottom:1px solid var(--rule);white-space:nowrap;
}
thead th a{color:inherit;text-decoration:none;display:inline-flex;gap:5px}
thead th a:hover{color:var(--ink)}
thead th[aria-sort] a{color:var(--accent)}
.arrow{font-size:8px;line-height:2}
td{padding:13px 14px;border-bottom:1px solid var(--line);vertical-align:middle;
   white-space:nowrap}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:var(--hover)}
td:first-child,th:first-child{padding-left:16px}
td:last-child,th:last-child{padding-right:16px}
.num{font-family:var(--mono);font-variant-numeric:tabular-nums;text-align:right}
.job{font-family:var(--mono);color:var(--mute)}
.strong{font-weight:600}
.empty{color:var(--faint)}

/* progress */
.bar{height:5px;border-radius:99px;background:#DEE0D9;overflow:hidden;
     min-width:70px;max-width:110px}
.bar span{display:block;height:100%;border-radius:99px;background:var(--accent)}
.barwrap{display:flex;align-items:center;gap:9px}
.barwrap .pct{font-family:var(--mono);font-size:11.5px;color:var(--mute);
              font-variant-numeric:tabular-nums;min-width:30px;text-align:right}

/* status pills — pip plus word, so greyscale and CVD both still read */
.pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;
      padding:4px 10px;border-radius:99px;background:var(--hover);
      color:var(--ink);white-space:nowrap}
.pip{width:7px;height:7px;border-radius:50%;flex:none}
.s-run  .pip{background:var(--good)}
.s-hold .pip{background:var(--warn)}
.s-late .pip{background:var(--crit)}
.s-done .pip{background:var(--faint)}
.s-late{background:#FBE9E7}
.s-hold{background:#F7EFDD}
.late-note{font-size:11.5px;color:var(--crit);margin-left:7px;
           font-variant-numeric:tabular-nums}

.nothing{padding:40px 16px;text-align:center;color:var(--mute)}

/* ---------------------------------------------------------------- login */
.login{min-height:100vh;display:grid;place-items:center;padding:40px 20px}
.card{width:100%;max-width:380px;background:var(--panel);
      border:1px solid var(--line);border-radius:var(--r);
      box-shadow:var(--shadow);padding:30px 28px;
      display:flex;flex-direction:column;gap:16px}
.card .brand{font-size:18px}
.card .brand .mark{width:24px;height:24px}
.card h1{margin:0;font-size:19px;font-weight:600;letter-spacing:-.01em}
.card p.lede{margin:-8px 0 0;color:var(--mute);font-size:14px}
.field{display:flex;flex-direction:column;gap:6px}
.field label{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;
             text-transform:uppercase;color:var(--mute)}
.field input{font:inherit;font-size:15px;padding:10px 12px;border-radius:var(--r);
             border:1px solid var(--line);background:var(--bg);color:var(--ink)}
.card .btn{width:100%;padding:11px}
.hint{font-size:12.5px;color:var(--faint);border-top:1px solid var(--line);
      padding-top:14px;margin:0}
.hint code{font-family:var(--mono);font-size:12px;background:var(--hover);
           padding:1px 5px;border-radius:3px;color:var(--mute)}

@media (max-width:760px){
  .wrap{padding:14px}
  .nav a{padding:7px 9px}
  .top{gap:12px;padding:0 14px}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ------------------------------------------------- properties table extras */
.mono{font-family:var(--mono);font-size:12.5px}
.nowrap{white-space:nowrap}
.wrapcell{white-space:normal;min-width:190px;max-width:280px;color:var(--mute);
          font-size:12.5px;line-height:1.4}
.links{white-space:nowrap}
.ref{display:inline-block;font-size:11.5px;padding:2px 7px;margin:1px 3px 1px 0;
     border-radius:99px;background:var(--accent-soft);color:var(--accent);
     text-decoration:none;border:1px solid transparent}
.ref:hover{border-color:var(--accent)}
.soon{font-size:11px;color:var(--crit);margin-left:6px;font-variant-numeric:tabular-nums}
.past{font-size:11px;color:var(--faint);margin-left:6px}
.gapnote{font-size:12.5px;color:var(--mute);margin-left:auto}
.foot{color:var(--mute);font-size:13px;margin:0;max-width:80ch}
.lede{font-size:16px;color:var(--mute);max-width:74ch;margin:0}

/* ------------------------------------------------------------ panels */
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
       box-shadow:var(--shadow);padding:20px 22px;display:flex;
       flex-direction:column;gap:12px}
.panel h2{margin:0;font-size:17px;font-weight:600;letter-spacing:-.01em}
/* 78ch is a sensible measure for a paragraph on its own. Under a
   full-width table it reads as a broken line: the text stops a third of
   the way across while the table beside it runs to the edge. Notes that
   belong to a table get a longer measure so they look like a caption for
   it rather than an orphan. */
.panel p{margin:0;max-width:78ch;font-size:14.5px}
.panel > table + .aside,
.panel > .aside:last-child,
.report + .aside{max-width:none}
.panel ul{margin:0;padding-left:20px;max-width:78ch;font-size:14.5px}
.panel li{margin-bottom:7px}
.panel code{font-family:var(--mono);font-size:12.5px;background:var(--hover);
            padding:1px 6px;border-radius:3px}
.panel.blank{align-items:flex-start;padding:34px 22px}
.panel.warn{border-left:3px solid var(--warn)}
.aside{color:var(--mute);font-size:13.5px!important}
table.plain{width:auto;min-width:0;font-size:14px}
table.plain td{border-bottom:1px solid var(--line);padding:9px 16px 9px 0;
               vertical-align:top;white-space:normal;max-width:62ch}
table.plain tr:last-child td{border-bottom:0}

/* --------------------------------------------------------- process steps */
.steps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1px;
       background:var(--line);border:1px solid var(--line);border-radius:var(--r);
       overflow:hidden}
.step{background:var(--panel);padding:16px 20px;display:grid;
      grid-template-columns:30px 1fr;gap:16px;align-items:start}
.step.you{background:var(--accent-soft)}
.mark{font-family:var(--mono);font-size:13px;font-weight:700;color:var(--accent);
      line-height:1.5}
.stepbody h3{margin:0 0 4px;font-size:15.5px;font-weight:600;
             display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.who-tag{font-family:var(--mono);font-size:10px;letter-spacing:.1em;
         text-transform:uppercase;color:var(--mute);border:1px solid var(--line);
         padding:2px 7px;border-radius:99px;font-weight:600;background:var(--bg)}
.step.you .who-tag{color:var(--accent);border-color:var(--accent)}
.stepbody p{margin:0;color:var(--mute);font-size:14px;max-width:78ch;line-height:1.55}
.stepbody b{color:var(--ink);font-weight:600}
.tool{display:inline-block;margin-top:7px;font-family:var(--mono);font-size:12px;
      background:var(--hover);padding:2px 7px;border-radius:3px;color:var(--mute)}

/* ------------------------------------------------------------ users page */
.pwform{display:flex;gap:6px;align-items:center}
.pwform input{font:inherit;font-size:13px;padding:5px 9px;border-radius:var(--r);
              border:1px solid var(--line);background:var(--bg);color:var(--ink);
              width:150px}

/* -------------------------------------------------- using a wide screen
   The notices table is edge-to-edge by nature — it has 27 columns to
   spend. The prose pages have to earn the same width with columns; a
   200-character line is not "full width", it is unreadable. */
.wrap{max-width:1760px;margin-inline:auto;width:100%}

.cols{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);
      border-radius:var(--r);overflow:hidden;margin-top:2px}
.cols>div{background:var(--panel);padding:15px 17px;display:flex;
          flex-direction:column;gap:5px}
.cols h4{margin:0;font-size:14px;font-weight:600;letter-spacing:-.01em}
.cols p{margin:0;font-size:13.5px;color:var(--mute);line-height:1.55;max-width:none}

@media (min-width:1180px){
  .steps{display:grid;grid-template-columns:1fr 1fr}
  .stepbody p{max-width:none}
  .cols{grid-template-columns:repeat(3,1fr)}
  .panel.split{display:grid;grid-template-columns:1fr 1fr;gap:14px 40px;
               align-items:start}
  .panel.split>h2{grid-column:1/-1}
  .panel.split>div{display:flex;flex-direction:column;gap:12px}
  .panel.split p,.panel.split ul{max-width:none}
}

/* Sale location — a Google Maps search, so a typed address lands on the
   pin when it resolves and on results when it doesn't. */
.place{color:inherit;text-decoration:none;border-bottom:1px solid var(--line)}
.place:hover{color:var(--accent);border-bottom-color:var(--accent)}

/* ------------------------------------------------------------- assistant */
.aibtn{position:fixed;right:20px;bottom:20px;z-index:40;
       display:flex;align-items:center;gap:8px;
       font:inherit;font-size:13px;font-weight:600;letter-spacing:.02em;
       color:#fff;background:var(--accent);border:0;cursor:pointer;
       padding:11px 17px;border-radius:99px;
       box-shadow:0 6px 22px rgba(23,96,92,.32)}
.aibtn:hover{filter:brightness(1.08)}
.aidot{width:7px;height:7px;border-radius:99px;background:#fff;opacity:.85}

.aipanel{position:fixed;right:20px;bottom:74px;z-index:41;
         width:min(440px,calc(100vw - 40px));height:min(620px,calc(100vh - 120px));
         display:flex;flex-direction:column;overflow:hidden;
         background:var(--panel);border:1px solid var(--line);
         border-radius:12px;box-shadow:0 18px 50px rgba(35,40,42,.22)}
.aipanel[hidden]{display:none}
.aipanel header{display:flex;align-items:baseline;gap:9px;flex:0 0 auto;
                padding:13px 14px;border-bottom:1px solid var(--line)}
.aititle{font-size:14px;font-weight:600}
.aisub{font-size:12px;color:var(--mute)}
.aiclear{margin-left:auto;font:inherit;font-size:12px;color:var(--mute);
         background:none;border:0;cursor:pointer;text-decoration:underline}
.aiclose{font:inherit;font-size:19px;line-height:1;color:var(--mute);
         background:none;border:0;cursor:pointer;padding:0 2px}
.aiclear:hover,.aiclose:hover{color:var(--ink)}

.ailog{flex:1 1 auto;overflow-y:auto;padding:14px;display:flex;
       flex-direction:column;gap:14px}
.aiempty p{margin:0 0 8px;font-size:13.5px;color:var(--ink)}
.aiempty .aieg{font-size:12.5px;color:var(--mute);line-height:1.55}
.aimsg{display:flex;flex-direction:column;gap:3px}
.aiwho{font-family:var(--mono);font-size:10px;letter-spacing:.1em;
       text-transform:uppercase;color:var(--faint)}
.aitext{font-size:13.5px;line-height:1.55;white-space:pre-wrap;
        overflow-wrap:anywhere}
.aimsg.user .aitext{background:var(--bg);border:1px solid var(--line);
                    border-radius:9px;padding:8px 11px;
                    max-height:180px;overflow:auto}
.aiwrites{display:flex;flex-direction:column;gap:3px;margin-top:6px}
.aiwrite{font-size:12px;color:var(--accent);background:var(--accent-soft);
         border-radius:6px;padding:5px 9px}
.aithinking{font-size:12.5px;color:var(--mute)}

.aiform{flex:0 0 auto;border-top:1px solid var(--line);padding:11px 12px;
        display:flex;flex-direction:column;gap:8px}
.aiform textarea{font:inherit;font-size:13.5px;line-height:1.5;resize:vertical;
                 min-height:62px;max-height:220px;padding:9px 11px;
                 border:1px solid var(--line);border-radius:8px;
                 background:var(--bg);color:var(--ink)}
.aiform textarea:focus{outline:2px solid var(--accent);outline-offset:-1px;
                       border-color:transparent}
.airow{display:flex;align-items:center;gap:10px}
.aihint{font-size:11.5px;color:var(--faint)}
.airow .btn{margin-left:auto}
.aiform textarea:disabled{opacity:.6}

@media (max-width:520px){
  .aipanel{right:10px;left:10px;width:auto;bottom:70px}
  .aibtn{right:12px;bottom:12px}
}
.aitext code{font-family:var(--mono);font-size:12px;background:var(--hover);
             padding:1px 5px;border-radius:3px}
.aitext b{font-weight:600;color:var(--ink)}

/* -------------------------------------------------------------- history */
.batch{background:var(--panel);border:1px solid var(--line);
       border-radius:var(--r);box-shadow:var(--shadow);overflow:hidden}
.batch.undone{opacity:.6}
.batchhead{display:flex;align-items:center;gap:12px;padding:11px 16px;
           border-bottom:1px solid var(--line)}
.batchhead .when{font-family:var(--mono);font-size:12.5px;color:var(--ink)}
.batchhead .bywho{font-size:12.5px;color:var(--mute)}
.batchhead form,.batchhead .pill{margin-left:auto}
table.diff{width:100%;font-size:13.5px}
table.diff td{border-bottom:1px solid var(--line);padding:8px 14px;
              white-space:nowrap;vertical-align:top}
table.diff tr:last-child td{border-bottom:0}
.diff .where{color:var(--mute);width:1%}
.diff .what{font-family:var(--mono);font-size:12.5px;width:1%}
.diff .was{color:var(--mute);text-decoration:line-through;
           max-width:34ch;overflow:hidden;text-overflow:ellipsis}
.diff .arrow{color:var(--faint);width:1%;text-align:center}
.diff .now{color:var(--ink);max-width:44ch;overflow:hidden;text-overflow:ellipsis}
.diff .how{color:var(--faint);font-size:12px;width:1%}
.src{border-top:1px solid var(--line)}
.src summary{cursor:pointer;padding:9px 16px;font-size:12.5px;color:var(--mute)}
.src pre{margin:0;padding:0 16px 14px;font-family:var(--mono);font-size:12px;
         color:var(--mute);white-space:pre-wrap;max-height:240px;overflow:auto}

/* ------------------------------------------------- staged, not yet written */
.aiprops{display:flex;flex-direction:column;gap:8px;margin-top:8px;
         border:1px solid var(--accent);border-radius:9px;padding:10px 11px;
         background:var(--accent-soft)}
.aiprophead{font-family:var(--mono);font-size:10px;letter-spacing:.09em;
            text-transform:uppercase;color:var(--accent)}
.aiprop{font-size:12.5px;line-height:1.5}
.aiprop .who{font-weight:600}
.aichg{display:flex;gap:6px;align-items:baseline;flex-wrap:wrap;
       font-size:12px;color:var(--mute)}
.aichg .f{font-family:var(--mono);font-size:11.5px;color:var(--ink)}
.aichg .to{color:var(--ink)}
.aichg .was{text-decoration:line-through}
.aichg.over .f{color:var(--warn)}
.aiwarn{font-size:11.5px;color:var(--warn)}
.aiacts{display:flex;gap:8px;align-items:center;margin-top:2px}
.aiacts .btn{padding:5px 12px;font-size:12.5px}
.aidiscard{font:inherit;font-size:12.5px;color:var(--mute);background:none;
           border:0;cursor:pointer;text-decoration:underline}
.aidone{font-size:12px;color:var(--accent)}

/* ---------------------------------------------------- gaps, made visible
   A cell nobody has filled yet is shaded the same muted yellow the
   spreadsheet uses, so a hole is visible while scanning rather than only
   when you stop and read the dash. Colour is not doing the work alone —
   the dash is still there. */
/* `.isgap` is set by the template for a cell that offers a way to go and
   find the value instead of printing a dash — it is still a gap, and has to
   look and filter like one. */
td:has(> .empty),
td.links:has(.empty),
td.isgap{background:var(--gap)}
tbody tr:hover td:has(> .empty),
tbody tr:hover td.links:has(.empty),
tbody tr:hover td.isgap{background:var(--gap-hover)}
/* The key under the table. Its own line, because a swatch dropped into the
   middle of a sentence breaks the line in an ugly place. */
.key{list-style:none;margin:2px 0 0;padding:0;display:flex;gap:22px;
     flex-wrap:wrap;font-size:12.5px;color:var(--mute)}
.key li{display:flex;align-items:center;gap:7px}
.key .sw{width:12px;height:12px;border-radius:3px;flex:none}
.key .sw.gap{background:var(--gap);border:1px solid var(--rule)}
.key .sw.done{background:transparent;border:1px solid var(--line)}
.key .find{margin-right:1px}

/* ----------------------------------------------- the two fillable cells */
td.findable{cursor:pointer}
td.findable:hover{background:var(--hover)}
td.findable:hover:has(.empty){background:var(--gap-hover)}
/* The cursor and the hover tint are enough of a hint; a word appearing on
   hover shifted the cell contents and read as data. */

/* ------------------------------------------------------------- the sheet */
.sheetback{position:fixed;inset:0;z-index:60;background:rgba(35,40,42,.34);
           display:grid;place-items:center;padding:20px}
.sheet{width:min(560px,100%);max-height:86vh;overflow:auto;background:var(--panel);
       border:1px solid var(--line);border-radius:12px;
       box-shadow:0 24px 60px rgba(35,40,42,.3)}
.sheet header{display:flex;align-items:baseline;gap:10px;padding:16px 18px;
              border-bottom:1px solid var(--line)}
.sheet h2{margin:0;font-size:16px;font-weight:600}
.sheet .addr{font-size:13px;color:var(--mute)}
.sheetx{margin-left:auto;font:inherit;font-size:21px;line-height:1;
        background:none;border:0;color:var(--mute);cursor:pointer}
.sheetx:hover{color:var(--ink)}
.sheetbody{padding:18px;display:flex;flex-direction:column;gap:20px}
.sheetbody .lab{display:block;font-family:var(--mono);font-size:10px;
                letter-spacing:.1em;text-transform:uppercase;color:var(--faint);
                margin-bottom:6px}
/* Square here, not a pill. The rounded shape reads as a small tag, which
   is right for the one-word pills in the table; at full-URL width wrapping
   onto two lines it turns into a lozenge with a lot of empty air in the
   corners. Padding stays tight — the box is there to group the text, not
   to frame it. Scoped to the modal so the table's pills keep their shape. */
.cur .ref,.found .ref{max-width:100%;overflow-wrap:anywhere;white-space:normal;
                      border-radius:2px;padding:3px 6px;margin:0}
.status:empty{display:none}
/* The state is a small label; the sentence itself stays in reading ink.
   A whole paragraph tinted amber is a paragraph nobody reads. */
.status{display:flex;flex-direction:column;align-items:flex-start;gap:10px;
        font-size:13.5px;line-height:1.62;color:var(--ink)}
.status .tag{font-family:var(--mono);font-size:10px;letter-spacing:.1em;
             text-transform:uppercase;padding:3px 9px;border-radius:99px;
             background:var(--hover);color:var(--mute);
             border:1px solid var(--line)}
.status .tag.work{color:var(--accent);border-color:var(--accent);
                  background:var(--accent-soft)}
.status .tag.miss{color:var(--warn);border-color:var(--warn)}
.status .msg{margin:0}
.found{display:flex;flex-direction:column;align-items:flex-start;gap:8px;
       margin-top:10px;padding:11px 12px;border:1px solid var(--accent);
       border-radius:9px;background:var(--accent-soft)}
.found .note{margin:0;font-size:13px;color:var(--mute);line-height:1.6}
.status .note{margin:0;width:100%;padding-top:11px;font-size:13px;
              color:var(--mute);line-height:1.6;border-top:1px solid var(--line)}
.manual{border-top:1px solid var(--line);padding-top:14px}
/* That rule divides "find it yourself" from the link already on the row.
   With no link and no status message there is nothing above it to divide,
   and it drew a line hard under the modal header. The selector is exact:
   the status box is first child only when the current-link block was not
   rendered, and :empty means no message is showing in it either. */
.sheetbody > .status:first-child:empty + .manual{border-top:0;padding-top:0}
.ownlinks{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.pasterow{display:flex;gap:8px}
.pasterow input{flex:1;font:inherit;font-size:13.5px;padding:8px 11px;
                border:1px solid var(--line);border-radius:var(--r);
                background:var(--bg);color:var(--ink);min-width:0}

/* ------------------------------------------------------------- dark mode
   Chosen steps, not an inversion. The ground keeps the warm grey-green cast
   it has in daylight, the accent is lifted because deep teal disappears on
   a dark ground, and the gap yellow becomes a low-chroma olive — a bright
   yellow on dark reads as an alarm, and a gap is not an alarm. */
@media (prefers-color-scheme: dark){ :root:not([data-theme="light"]){
  --bg:#191C1B; --panel:#212524; --ink:#E7EAE6; --mute:#9AA39E;
  --faint:#77817C; --line:#333937; --rule:#414744; --hover:#2A2F2D;
  --accent:#5FBDB2; --accent-soft:#23332F; --onaccent:#12201D;
  --good:#4FBF63; --warn:#D9A441; --crit:#E5695F;
  --gap:#2E2C1F; --gap-hover:#38351F;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 1px 1px rgba(0,0,0,.3);
}}
:root[data-theme="dark"]{
  --bg:#191C1B; --panel:#212524; --ink:#E7EAE6; --mute:#9AA39E;
  --faint:#77817C; --line:#333937; --rule:#414744; --hover:#2A2F2D;
  --accent:#5FBDB2; --accent-soft:#23332F; --onaccent:#12201D;
  --good:#4FBF63; --warn:#D9A441; --crit:#E5695F;
  --gap:#2E2C1F; --gap-hover:#38351F;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 1px 1px rgba(0,0,0,.3);
}
:root[data-theme="dark"] .aibtn{color:var(--onaccent)}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .aibtn{color:var(--onaccent)}
}

.themetoggle{display:flex;align-items:center;justify-content:center;
             width:30px;height:30px;padding:0;border-radius:99px;
             border:1px solid var(--line);background:var(--panel);
             color:var(--mute);cursor:pointer}
.themetoggle:hover{color:var(--ink);border-color:var(--rule)}
.themetoggle svg{width:15px;height:15px;fill:currentColor}
.themetoggle .moon{display:none}
:root[data-theme="dark"] .themetoggle .moon{display:block}
:root[data-theme="dark"] .themetoggle .sun{display:none}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .themetoggle .moon{display:block}
  :root:not([data-theme="light"]) .themetoggle .sun{display:none}
}

/* ---------------------------------------------------------------- admin */
.panel.danger{border-left:3px solid var(--crit)}
.panel.danger h2{color:var(--crit)}
.clearform{display:flex;flex-direction:column;align-items:flex-start;gap:6px;
           margin-top:4px}
.clearform label{font-size:13px;color:var(--mute)}
.clearform label+input{margin-bottom:8px}
.clearform input{font:inherit;font-size:14px;padding:8px 11px;width:min(320px,100%);
                 border:1px solid var(--line);border-radius:var(--r);
                 background:var(--bg);color:var(--ink)}
.clearform input:focus{outline:2px solid var(--crit);outline-offset:-1px;
                       border-color:transparent}
.btn.bad{margin-top:6px;background:var(--crit);border-color:var(--crit);color:#fff}
.btn.bad:hover{filter:brightness(1.06)}

/* ------------------------------------------------------------ the + button */
.add{position:relative;width:28px;height:28px;flex:none;font:inherit;
     line-height:1;padding:0;border-radius:50%;
     display:grid;place-items:center;
     /* The circle sits on the optical centre of the word — between its
        cap-height and baseline, not the line box, which carries descender
        space the word "Notices" never uses. */
     top:-1px;
     border:1px solid var(--line);background:var(--panel);color:var(--mute);
     cursor:pointer}
.add:hover{color:var(--accent);border-color:var(--accent)}
.add svg{width:13px;height:13px;display:block}
.add .dot{position:absolute;top:-5px;right:-5px;min-width:16px;height:16px;
          padding:0 4px;border-radius:99px;background:var(--accent);
          color:var(--onaccent);font-family:var(--mono);font-size:10px;
          line-height:16px;font-weight:600}

/* ------------------------------------------------------------ the inbox */
.sheet.wide{width:min(680px,100%)}
.drop{border:1.5px dashed var(--rule);border-radius:10px;padding:26px 20px;
      display:flex;flex-direction:column;align-items:center;gap:7px;
      text-align:center;background:var(--bg)}
.drop.over{border-color:var(--accent);background:var(--accent-soft)}
.drop strong{font-size:14.5px;font-weight:600}
.drop .hint{font-size:12.5px;color:var(--mute)}
.drop .btn{margin-top:6px}
.queue{display:flex;flex-direction:column;gap:10px}
.queue:empty{display:none}
.qhead{font-family:var(--mono);font-size:10px;letter-spacing:.09em;
       text-transform:uppercase;color:var(--faint)}
.qitem{border:1px solid var(--line);border-radius:9px;padding:11px 12px;
       background:var(--bg);display:flex;flex-direction:column;gap:8px}
.qitem.done{opacity:.72}
.qtop{display:flex;align-items:center;gap:9px}
.qname{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;
       white-space:nowrap}
.qsize{font-family:var(--mono);font-size:11px;color:var(--faint)}
.qstate{margin-left:auto;font-family:var(--mono);font-size:10.5px;
        letter-spacing:.08em;text-transform:uppercase;color:var(--mute)}
.qstate:empty{display:none}
.qtop .btn{margin-left:auto}
.qstate:not(:empty)+.btn{margin-left:0}
.qout{display:flex;flex-direction:column;gap:9px}
.qout:empty{display:none}
.qmsg{margin:0;font-size:13px;line-height:1.6;color:var(--ink);
      white-space:pre-wrap}
.qmsg.bad{color:var(--warn)}

/* A capture being read. There is no real progress to report — the API does
   not give any — so this is a heartbeat, not a measurement. */
.qitem.busy{position:relative;overflow:hidden}
.qitem.busy::after{content:"";position:absolute;left:0;right:0;bottom:0;
                   height:2px;background:var(--accent-soft);overflow:hidden}
.qitem.busy::before{content:"";position:absolute;bottom:0;left:0;height:2px;
                    width:34%;background:var(--accent);z-index:1;
                    animation:sweep 1.4s ease-in-out infinite}
@keyframes sweep{
  0%{transform:translateX(-100%)}
  100%{transform:translateX(340%)}
}
@media (prefers-reduced-motion:reduce){
  .qitem.busy::before{animation:none;width:100%;opacity:.45}
}
.sheetacts{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.sheetacts .aside{font-size:12.5px;color:var(--mute);flex:1;min-width:200px}

/* --------------------------------------------------------- column filter */
.colbar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
        margin:-4px 0 -2px}
.colbar .seg a{cursor:pointer}
.switch{display:inline-flex;align-items:center;gap:7px;font-size:13px;
        color:var(--mute);cursor:pointer;user-select:none}
.switch input{accent-color:var(--accent);width:15px;height:15px;margin:0}
.colcount{font-size:12.5px;color:var(--faint);
          font-variant-numeric:tabular-nums}
.colpick{margin-left:auto;position:relative}
.colpick summary{list-style:none;cursor:pointer;font-size:13px;
                 color:var(--mute);padding:5px 11px;border-radius:var(--r);
                 border:1px solid var(--line);background:var(--panel)}
.colpick summary::-webkit-details-marker{display:none}
.colpick[open] summary{color:var(--ink);border-color:var(--rule)}
.colgrid{position:absolute;right:0;top:calc(100% + 6px);z-index:20;
         width:min(460px,86vw);max-height:66vh;overflow:auto;
         padding:12px 14px 14px;background:var(--panel);
         border:1px solid var(--line);border-radius:var(--r);
         box-shadow:0 12px 34px rgba(35,40,42,.18)}
.fillrow{display:flex;align-items:center;gap:10px;padding-bottom:11px;
         margin-bottom:10px;border-bottom:1px solid var(--line)}
.fillrow .lab{font-family:var(--mono);font-size:10px;letter-spacing:.1em;
              text-transform:uppercase;color:var(--faint)}
.fillrow .seg{flex-wrap:wrap}
.collist{display:grid;grid-template-columns:repeat(2,1fr);gap:2px 14px}
.collist label{display:flex;align-items:center;gap:7px;font-size:13px;
               padding:3px 0;cursor:pointer}
.collist input{accent-color:var(--accent);width:14px;height:14px;margin:0}
/* A firm we have not checked a website for — the link is a search. */
.place.guess{border-bottom-style:dotted}

/* -------------------------------------------------- bugs and requests */
.navdot{margin-left:6px;padding:1px 6px;border-radius:99px;
        background:var(--accent);color:var(--onaccent);
        font-family:var(--mono);font-size:10px;font-weight:600}

.bugbtn{position:fixed;left:20px;bottom:20px;z-index:40;
        font:inherit;font-size:12.5px;color:var(--mute);
        background:var(--panel);border:1px solid var(--line);
        padding:9px 14px;border-radius:99px;cursor:pointer;
        box-shadow:var(--shadow)}
.bugbtn:hover{color:var(--ink);border-color:var(--rule)}

.reqline{font:inherit;font-size:14.5px;padding:9px 11px;border-radius:var(--r);
         border:1px solid var(--line);background:var(--bg);color:var(--ink)}
.sheetbody textarea{font:inherit;font-size:13.5px;line-height:1.55;
                    padding:9px 11px;border-radius:var(--r);resize:vertical;
                    border:1px solid var(--line);background:var(--bg);
                    color:var(--ink)}
.reqline:focus,.sheetbody textarea:focus{outline:2px solid var(--accent);
                    outline-offset:-1px;border-color:transparent}
.thanks{align-items:flex-start}
.thanks h2{margin:0;font-size:17px}

.req{background:var(--panel);border:1px solid var(--line);
     border-radius:var(--r);box-shadow:var(--shadow);padding:14px 16px;
     display:flex;flex-direction:column;gap:8px}
.req.done,.req.declined{opacity:.6}
.reqhead{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.reqtitle{font-size:14.5px;font-weight:600}
.reqdetail{margin:0;font-size:13.5px;line-height:1.6;color:var(--mute);
           white-space:pre-wrap;max-width:90ch}
.reqfoot{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
         font-size:12px;color:var(--faint)}
.reqfoot .acts{margin-left:auto;display:flex;gap:7px}
.reqfoot .btn{padding:4px 10px;font-size:12px}
.k-bug .pip{background:var(--crit)}
.k-feat .pip{background:var(--accent)}
.s-done{color:var(--mute)}


/* Paste straight into the inbox */
.pastebox{display:flex;flex-direction:column;gap:8px}
.pastebox textarea{font:inherit;font-size:13.5px;line-height:1.55;
                   padding:10px 12px;border-radius:var(--r);resize:vertical;
                   min-height:96px;border:1px solid var(--line);
                   background:var(--bg);color:var(--ink)}
.pastebox textarea:focus{outline:2px solid var(--accent);outline-offset:-1px;
                         border-color:transparent}
.pasteact{display:flex;align-items:center;gap:11px;flex-wrap:wrap}
.pasteact .aside{font-size:12.5px;color:var(--mute);flex:1;min-width:210px}
/* An empty listing cell still gives you a way onto the page. Quieter than a
   filled pill, so a row with real links still reads as more complete. */
.find{display:inline-flex;align-items:stretch;font-size:11.5px;
      border-radius:99px;border:1px dashed var(--line);overflow:hidden;
      color:var(--mute)}
.findword{padding:2px 7px 2px 9px;cursor:pointer}
.findgo{padding:2px 8px 2px 5px;text-decoration:none;color:inherit;
        border-left:1px dashed var(--line)}
td.findable:hover .find{border-color:var(--accent);border-style:solid;
                        color:var(--accent)}
td.findable:hover .findgo{border-left-color:var(--accent)}
.findgo:hover{background:var(--accent-soft)}
/* Plain-English opener on the add-notices modal */
.intro{display:flex;flex-direction:column;gap:7px;padding-bottom:2px}
.intro strong{font-size:15px;font-weight:650;line-height:1.4;
              letter-spacing:-.01em}
.intro p{margin:0;font-size:13.5px;line-height:1.6;color:var(--mute);
         max-width:62ch}

/* An answered "there is nothing to find" — grey, not yellow. It is settled,
   so it neither shades nor counts against the gaps. */
.na{font-size:12px;color:var(--mute);font-style:italic}
td.settled{background:transparent}

/* ------------------------------------------------------------------ zoom */
.zoom{display:inline-flex;align-items:stretch;border:1px solid var(--line);
      border-radius:99px;overflow:hidden;background:var(--panel)}
.zoom button{font:inherit;font-size:14px;line-height:1;width:26px;height:28px;
             padding:0;border:0;background:none;color:var(--mute);
             cursor:pointer;display:grid;place-items:center}
.zoom button:hover{color:var(--ink);background:var(--hover)}
.zoom button+button{border-left:1px solid var(--line)}
.zoom .lvl{font-family:var(--mono);font-size:10.5px;color:var(--faint);
           display:grid;place-items:center;padding:0 6px;min-width:38px}
/* Caption under its button, not beside it — a line of explanation reads as
   belonging to the control above it. */
.norow{display:flex;flex-direction:column;align-items:flex-start;gap:6px;
       margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
.norow .aside{font-size:12.5px;color:var(--mute);line-height:1.5}

/* Two audiences, two halves. */
.part{margin:12px 0 4px;font-family:var(--mono);font-size:10px;
      letter-spacing:.1em;text-transform:uppercase;font-weight:600}
.part:first-child{margin-top:0}
.part.office{color:var(--accent)}
.part.dev{color:var(--faint)}
.partbody{margin:0;font-size:13.5px;line-height:1.6;white-space:pre-wrap}
.part.dev+.partbody{color:var(--mute);font-size:13px}

/* Taking a row off the board — the only destructive thing the assistant can
   propose, so it is dressed as one. */
.archwarn{border:1px solid var(--crit);border-radius:9px;padding:10px 12px;
          display:flex;flex-direction:column;gap:6px;background:var(--panel)}
.archwarn strong{font-size:13px;color:var(--crit)}
.archwarn p{margin:0;font-size:12.5px;color:var(--mute);line-height:1.55}
.archwarn input{font:inherit;font-size:13px;padding:6px 10px;width:150px;
                border:1px solid var(--line);border-radius:var(--r);
                background:var(--bg);color:var(--ink);letter-spacing:.08em}
.archwarn input:focus{outline:2px solid var(--crit);outline-offset:-1px;
                      border-color:transparent}

/* The key under the table, on its own line. */
.key{list-style:none;margin:2px 0 0;padding:0;display:flex;gap:24px;
     flex-wrap:wrap;font-size:12.5px;color:var(--mute)}
.key li{display:flex;align-items:center;gap:8px}
.key .sw{width:12px;height:12px;border-radius:3px;flex:none}
.key .sw.gap{background:var(--gap);border:1px solid var(--rule)}
.key .sw.done{background:transparent;border:1px solid var(--line)}
.tile.urgent .val{color:var(--crit)}
/* A tile waiting to be given a job. Reads as unfinished on purpose. */
.tile.empty{border-style:dashed;box-shadow:none;background:transparent}
.tile.empty .lab,.tile.empty .note{color:var(--faint)}
.tile.empty .val{color:var(--line)}

/* History filter + paging */
.histfilter{margin-left:auto}
.histfilter select{font:inherit;font-size:13px;padding:6px 10px;
                   border:1px solid var(--line);border-radius:var(--r);
                   background:var(--panel);color:var(--ink);max-width:280px}
.more{margin:2px 0 0}
.section{margin:8px 0 -6px;font-size:15px;font-weight:600;letter-spacing:-.01em}
.section+.tablewrap{margin-top:0}

/* Claude panel on the admin page */
.claudegrid{display:grid;gap:22px 34px;grid-template-columns:1fr}
/* A grid item will not shrink below the intrinsic width of its content
   unless it is told it may, and a <select> is as wide as its longest
   option — "Sonnet 5 (the default, and about a fifth the price…)". That
   one option held the Admin page at 473px on a phone, with max-width:100%
   on the select doing nothing, because the track itself had grown. */
.claudegrid > *{min-width:0}
.claudeform select{width:100%}
@media (min-width:900px){.claudegrid{grid-template-columns:1fr 1fr}}
.claudegrid .lab{display:block;font-family:var(--mono);font-size:10px;
                 letter-spacing:.1em;text-transform:uppercase;
                 color:var(--faint);margin-bottom:5px}
.claudegrid .ok{color:var(--accent);font-size:14px}
.claudegrid .bad{color:var(--crit);font-size:14px}
.claudeform{display:flex;flex-direction:column;align-items:flex-start;gap:7px}
.claudeform label{font-size:13px;color:var(--mute)}
.claudeform select{font:inherit;font-size:13.5px;padding:7px 10px;
                   border:1px solid var(--line);border-radius:var(--r);
                   background:var(--bg);color:var(--ink);max-width:100%}
.claudeform .btn{margin-top:4px}
.claudeform input[type=password]{font:inherit;font-size:13px;padding:7px 10px;
    width:min(340px,100%);border:1px solid var(--line);border-radius:var(--r);
    background:var(--bg);color:var(--ink)}
.usage{border-top:1px solid var(--line);padding-top:14px;margin-top:4px}
.usage .lab{display:block;font-family:var(--mono);font-size:10px;
            letter-spacing:.1em;text-transform:uppercase;color:var(--faint);
            margin-bottom:7px}
.usagerow{display:flex;gap:26px;flex-wrap:wrap;font-size:13.5px;
          color:var(--mute)}
.usagerow b{font-size:17px;color:var(--ink);font-variant-numeric:tabular-nums}
.usagetable{margin-top:12px;font-size:13px}
.usagetable td{padding:5px 18px 5px 0}
.usagetable .num{font-variant-numeric:tabular-nums;text-align:right}

/* ---------------------------------------------------------------- reports */
table.report{width:100%;font-size:13.5px}
table.report th{padding:0 14px 8px 0;border-bottom:1px solid var(--rule);
                font-family:var(--mono);font-size:10px;letter-spacing:.09em;
                text-transform:uppercase;color:var(--mute);text-align:left;
                white-space:nowrap}
table.report td{padding:10px 14px 10px 0;border-bottom:1px solid var(--line);
                vertical-align:top}
table.report tr:last-child td{border-bottom:0}
table.report .num{text-align:right;font-variant-numeric:tabular-nums;
                  white-space:nowrap}
table.report th.num{text-align:right}
.report .quiet{color:var(--faint);font-size:12.5px}
.report .soon{color:var(--crit);font-size:12px;margin-left:5px}
.report .good{color:var(--good)}
.report .need{display:inline-flex;align-items:baseline;gap:5px;
              margin:0 6px 4px 0;padding:2px 8px;border-radius:99px;
              background:var(--gap);font-size:12px}
.report .need i{font-style:normal;color:var(--faint);font-size:11px}
.panel .lede{font-size:14px}

/* ------------------------------------------------------------ sample charts
   Two series, two steps, both validated against their own surface rather
   than one being flipped from the other. The app accent is not used as a
   mark: at OKLCH chroma 0.069 it reads grey. */
:root{--s1:#008B7E; --s2:#B8501C;
      --gridline:#E2E4DD; --axisline:#C6C9C0}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){--s1:#2AA096; --s2:#CE7840;
      --gridline:#2E3432; --axisline:#414744}
}
:root[data-theme="dark"]{--s1:#2AA096; --s2:#CE7840;
      --gridline:#2E3432; --axisline:#414744}

.panel.sample{gap:22px}
.chart{margin:0}
.chart figcaption{font-size:14px;font-weight:600;margin-bottom:10px}
/* Two to a row rather than one column down a 1500px page: that left half
   the panel empty and stretched each drawing to twice its intended size,
   so every label came out twice the size of the page's own type. At two
   columns a cell is close to the 720-unit viewBox, so one unit is about
   one pixel and the text lands where it was drawn. */
.charts{display:grid;gap:40px 36px;max-width:1560px}
/* Two to a row above 980px, never three: a third column would squeeze the
   twelve-month chart and the property labels into something unreadable,
   and one column down a wide page leaves half the panel empty. */
@media (min-width:980px){
  .charts{grid-template-columns:repeat(2,minmax(0,1fr))}
}
.chart svg{width:100%;height:auto;overflow:visible;display:block}
.chart .s1{fill:var(--s1)}
.chart .s2{fill:var(--s2)}
.chart .grid{stroke:var(--gridline);stroke-width:1}
.chart .axis{stroke:var(--axisline);stroke-width:1}
/* Chart text is page text: same family, muted ink, never a series colour. */
.chart text{font-family:var(--sans)}
.chart .tick{fill:var(--faint);font-size:11px;
             font-variant-numeric:tabular-nums}
.chart .value{fill:var(--mute);font-size:11px;
              font-variant-numeric:tabular-nums}
.chart .rowlabel{fill:var(--ink);font-size:12.5px}
.chart .mark:hover rect{opacity:.82}
.legend{display:flex;gap:18px;margin:-2px 0 10px;font-size:12.5px;
        color:var(--mute)}
.legend i{display:inline-block;width:11px;height:11px;border-radius:3px;
          margin-right:6px;vertical-align:-1px}
.legend .s1{background:var(--s1)}
.legend .s2{background:var(--s2)}
.tableview summary{cursor:pointer;font-size:13px;color:var(--mute)}
.tvgrid{display:grid;gap:20px;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
        margin-top:12px}
.tvgrid .num{text-align:right;font-variant-numeric:tabular-nums}
.btn:disabled{opacity:.55;cursor:default}
.btn:disabled:hover{filter:none;border-color:var(--line)}
.cool{font-size:12.5px;color:var(--faint)}

/* ------------------------------------------------------ printable report
   One card per sale, built to be printed and carried to an auction.

   Screen and paper are different jobs and this is written for paper first:
   hairline rules, no fills behind text, everything in a grid that survives
   losing colour. On screen it borrows the panel treatment so it does not
   look like a different application.

   The links are deliberately absent. On paper a URL is four lines of slug
   and nothing to click; the source's *name* is what tells you where to go. */
.printwrap{max-width:1100px}

.printhead{display:none}

.pcard{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
       padding:20px 22px 16px;margin-top:16px;
       /* Never let a card be split down the middle by a page break. */
       break-inside:avoid;page-break-inside:avoid}

.pcardhead{display:flex;gap:18px;align-items:flex-start;
           padding-bottom:14px;border-bottom:1px solid var(--line)}
.pwho h2{margin:0;font-size:17px;font-weight:600;letter-spacing:-.01em}
.pwho .ptown{color:var(--mute);font-size:13px}
.pwhen{margin-left:auto;text-align:right;flex:0 0 auto;
       padding-left:18px;border-left:2px solid var(--accent)}
.pdate{display:block;font-size:15px;font-weight:600;
       font-variant-numeric:tabular-nums}
.ptime{display:block;color:var(--mute);font-size:12.5px;
       font-variant-numeric:tabular-nums}

/* A band, not a heading: it separates without competing with the address. */
.pband{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;
       text-transform:uppercase;color:var(--faint);
       margin:16px 0 9px;padding-bottom:5px;
       border-bottom:1px solid var(--rule)}

.pgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px 20px}
.pfield{min-width:0}
.pfield.w2{grid-column:span 2}
.plab{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;
      text-transform:uppercase;color:var(--faint);margin-bottom:3px}
.pval{font-size:13px;line-height:1.45;overflow-wrap:anywhere;
      font-variant-numeric:tabular-nums}
/* An em dash is the finding "nobody has this yet", so it should read as
   quieter than a value without vanishing. */
.pval.none{color:var(--faint)}

.pnotes{margin:0;font-size:12.5px;line-height:1.65;color:var(--mute)}

.pblanks{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;
         margin-top:18px}
.pblanks span{display:block}
.pblanks i{font-style:normal}
.pblanks b{display:block;height:19px;border-bottom:1px solid var(--line)}

.pcardfoot{display:flex;gap:16px;margin-top:14px;padding-top:10px;
           border-top:1px solid var(--rule);
           font-family:var(--mono);font-size:10px;letter-spacing:.06em;
           text-transform:uppercase;color:var(--faint)}
.pcardfoot span:last-child{margin-left:auto}

@media (max-width:760px){
  .pgrid{grid-template-columns:repeat(2,1fr)}
  .pfield.w2{grid-column:span 2}
}

@media print{
  /* Paper has its own ground. Anything that was a surface on screen becomes
     an outline, so a card costs a hairline of toner instead of a fill. */
  :root{--ink:#111;--mute:#3A3A3A;--faint:#666;--line:#BBB;--rule:#DDD}
  html,body{background:#fff!important;color:#111!important}
  .nav,.noprint,.aibtn,.reqbtn,.flash,footer{display:none!important}
  .wrap{padding:0!important;max-width:none!important}

  .printhead{display:flex;align-items:baseline;gap:14px;
             padding-bottom:8px;margin-bottom:4px;
             border-bottom:1.5px solid #111}
  .ph-name{font-weight:600;font-size:13px;letter-spacing:.02em}
  .ph-what{font-size:11px;color:#3A3A3A}
  .ph-when{margin-left:auto;font-size:11px;color:#3A3A3A}

  .pcard{background:none;border:1px solid #BBB;border-radius:0;
         padding:14px 16px 10px;margin-top:12px}
  .pwhen{border-left-width:3px;border-left-color:#111}
  .pval{font-size:11.5px}
  .plab,.pband{color:#555}
  .pnotes{font-size:10.5px;color:#333}
  /* Room to write is the reason it is on paper at all — keep it generous
     when the screen padding is being cut back. */
  .pblanks b{height:22px;border-bottom-color:#999}
  a{text-decoration:none;color:inherit}
}

@page{margin:14mm 12mm}

/* ====================================================================== */
/* Phones                                                                  */
/*                                                                         */
/* Measured at 375px, not guessed: every page was scrolling sideways —     */
/* 784px of content in a 375px window — and it was the header bar doing    */
/* it, not the tables. The board's table is already inside a scroller and  */
/* was behaving; the top bar is one flex row that never wrapped, so the    */
/* nav and the controls simply ran off the edge and dragged the whole      */
/* document with them.                                                     */
/* ====================================================================== */
@media (max-width:760px){

  /* The bar wraps instead of running off. The nav drops to its own line
     and scrolls sideways within itself if the labels do not fit, which
     keeps the sideways scrolling inside the one element that can afford
     it rather than in the page. */
  .top{height:auto;min-height:52px;flex-wrap:wrap;align-items:center;
       padding:8px 14px;gap:6px 12px}
  .nav{order:3;width:100%;margin-left:0;gap:2px;
       overflow-x:auto;-webkit-overflow-scrolling:touch;
       scrollbar-width:none}
  .nav::-webkit-scrollbar{display:none}
  /* 40px tall: a finger, not a mouse pointer. */
  .nav a{padding:10px 12px;white-space:nowrap;font-size:14.5px}
  .top .right{margin-left:auto;gap:12px}

  /* The zoom control is a desktop affordance — a phone pinches, and these
     were 26px targets besides. The setting still applies if it was set on
     a desktop; only the buttons are hidden. */
  .zoom{display:none}

  .themetoggle{width:38px;height:38px}
  .add{width:38px;height:38px;font-size:20px}

  /* Page headings: the controls that sat to the right go under the title
     and take the full width, rather than squeezing it to nothing. */
  .head form{margin-left:0;width:100%;flex-wrap:wrap}
  .head h1{font-size:20px}

  /* 16px or iOS zooms the whole page the moment a field is focused, and
     then never zooms back. Every input here was 13.5px.
     !important because a dozen component rules set their own size with a
     class selector and beat a bare element one. This is not a preference
     being overridden — below 16px the platform takes the page away from
     the user, so it has to win. */
  input,select,textarea{font-size:16px!important}
  .btn{font-size:15px;padding:9px 14px}
}

@media (max-width:560px){

  /* The change log was a six-column table 1040px wide with no scroller,
     so it pushed the page sideways on its own. On a phone each change
     becomes a small stack: where, what, then old above new. The arrow
     goes — it is pointing across a gap that no longer exists. */
  table.diff, table.diff tbody, table.diff tr, table.diff td{
    display:block;width:auto;max-width:none}
  table.diff tr{padding:10px 0;border-bottom:1px solid var(--line)}
  table.diff tr:last-child{border-bottom:0}
  table.diff td{border:0;padding:1px 0}
  .diff .arrow{display:none}
  .diff .where{font-weight:600}
  .diff .was::before{content:"was ";font-family:var(--mono);font-size:10px;
                     letter-spacing:.08em;text-transform:uppercase;
                     color:var(--faint);text-decoration:none;
                     display:inline-block;margin-right:4px}
  .diff .now::before{content:"now ";font-family:var(--mono);font-size:10px;
                     letter-spacing:.08em;text-transform:uppercase;
                     color:var(--faint);display:inline-block;margin-right:4px}
  .diff .now{white-space:normal;overflow:visible;text-overflow:clip}
  .diff .how:empty{display:none}

  /* One card column, and the report cards likewise. */
  .pgrid{grid-template-columns:1fr}
  .pfield.w2{grid-column:span 1}
  .pblanks{grid-template-columns:1fr;gap:10px}
  .pcardhead{flex-wrap:wrap}
  .pwhen{margin-left:0;padding-left:12px}
}

/* ---------------------------------------------------------------------- */
/* The board, on a phone                                                   */
/*                                                                         */
/* 31 columns and 4,617px of table. Sideways scrolling is the right answer */
/* on a desk, where the columns are being read against each other; it is   */
/* the wrong one in a hand, where you swipe past the row heading and lose  */
/* track of which property you are looking at.                             */
/*                                                                         */
/* Each row becomes a card. Town and address lead, the sale date sits      */
/* opposite, and only the fields that have a value are listed. mobile.js   */
/* stamps the labels and marks the empty cells; if it has not run, none of */
/* this applies and the table behaves exactly as it did.                   */
/* ---------------------------------------------------------------------- */
@media (max-width:700px){
  .tablewrap:has(table.cardable){overflow:visible;border:0;background:none}

  /* The base rule sets min-width:1040px so the desktop table never
     collapses its columns. In card form there are no columns to protect,
     and that min-width was single-handedly keeping the page 1,040px wide
     after everything else had been fixed. */
  table.cardable, table.cardable tbody{display:block;width:100%;min-width:0}
  table.cardable thead{display:none}

  table.cardable tr{
    display:grid;grid-template-columns:minmax(0,1fr) auto;
    gap:1px 12px;align-items:baseline;
    background:var(--panel);border:1px solid var(--line);
    border-radius:var(--r);padding:13px 14px;margin-bottom:10px}

  /* The heading: identity on the left, when it sells on the right. */
  table.cardable td{display:block;border:0;padding:0;white-space:normal}
  table.cardable td.c-town{grid-column:1;grid-row:1;
                           font-weight:600;font-size:15.5px}
  table.cardable td.c-addr{grid-column:1;grid-row:2;
                           font-size:14px;color:var(--mute)}
  table.cardable td.c-date{grid-column:2;grid-row:1;text-align:right;
                           font-weight:600;font-variant-numeric:tabular-nums}
  table.cardable td.c-time{grid-column:2;grid-row:2;text-align:right;
                           font-size:13px;color:var(--mute);
                           font-variant-numeric:tabular-nums}

  /* Everything else: a labelled line, full width, under a hairline. */
  /* flex-wrap matters: a cell holding several chips (the "still needed"
     list) puts each one in as a flex item, and an unwrapped row of them
     runs straight off the side of the phone. */
  table.cardable td.c-field{
    grid-column:1 / -1;
    display:flex;justify-content:space-between;align-items:baseline;
    flex-wrap:wrap;gap:4px 14px;padding:6px 0;
    border-top:1px solid var(--rule);font-size:13.5px;text-align:left}
  table.cardable td.c-field::before{
    content:attr(data-label);
    font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;
    text-transform:uppercase;color:var(--faint);
    flex:0 0 auto;padding-top:2px}

  /* An unknown is worth seeing on a desk and worth hiding in a hand. */
  table.cardable td.blank{display:none}

  /* The first listed field sits right under the heading, so it does not
     need a rule above it as well as the gap. */
  table.cardable td.c-time ~ td.c-field:first-of-type{border-top:0}

  table.cardable td.num{text-align:right}
  table.cardable .findable{cursor:pointer}
  /* The link pills keep their own shape but stop stretching the line. */
  table.cardable td.links .ref{max-width:60vw;overflow-wrap:anywhere}
}

/* The report tables get the same treatment: three to five columns each,
   and all of them inherited the 1040px min-width meant to stop the board's
   31 columns collapsing. The first column is what the row is about, so it
   leads; the rest become labelled lines under it. */
@media (max-width:700px){
  table.report.cardable, table.report.cardable tbody{
    display:block;width:100%;min-width:0}
  table.report.cardable thead{display:none}
  table.report.cardable tr{display:block;background:var(--panel);
    border:1px solid var(--line);border-radius:var(--r);
    padding:12px 14px;margin-bottom:9px}
  table.report.cardable td{display:flex;justify-content:space-between;
    align-items:baseline;flex-wrap:wrap;gap:4px 14px;border:0;padding:5px 0;
    border-top:1px solid var(--rule);font-size:13.5px;text-align:left;
    white-space:normal;max-width:none}
  table.report.cardable td::before{content:attr(data-label);
    font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;
    text-transform:uppercase;color:var(--faint);flex:0 0 auto;padding-top:2px}
  table.report.cardable td.c-lead{display:block;border-top:0;padding:0 0 4px;
    font-weight:600;font-size:15px}
  table.report.cardable td.c-lead::before{content:none}
  table.report.cardable td.blank{display:none}
  table.report.cardable td.wrapcell{max-width:none}
}

/* Tables that need room for their columns on a desk. Stated here rather
   than inline on the element: an inline min-width cannot be relaxed by a
   media query, and that alone kept the Admin page 834px wide on a phone
   after everything else had been fixed. */
table.wide{min-width:820px}
@media (max-width:700px){
  table.wide.cardable{min-width:0}
  /* Cards that lead with a name rather than a town and a date. */
  table.cardable td.c-lead{grid-column:1 / -1;display:block;border-top:0;
    padding:0 0 4px;font-weight:600;font-size:15px}
  table.cardable td.c-lead::before{content:none}
}

/* On a phone the bug/feature pill is 400px of fixed furniture sitting on
   top of whatever you are reading. It keeps its job and loses its sentence
   — the plus is the same affordance, and the modal it opens says the rest. */
@media (max-width:700px){
  .bugbtn{font-size:0;width:44px;height:44px;padding:0;border-radius:50%;
          display:grid;place-items:center}
  .bugbtn::after{content:"?";font-size:18px;font-weight:600;line-height:1}
}
