/* ChartFill review UI. Extracted from the template so the page needs no
   'unsafe-inline' in its Content-Security-Policy. See app.py. */
:root, :root[data-palette="navy"]{
  --ds-deep:#0E2C4F; --ds-base:#17457C; --ds-lit:#3B8FD4; --ds-mist:#C7D8E9;
  --ds-paper:#EAF1F8; --ds-ink:#0F1B2A; --ds-ink-muted:#54657E; --ds-line:#E2E9F1; --ds-card:#fff;
}
:root[data-palette="teal"]{
  --ds-deep:#0B3D31; --ds-base:#0F6E56; --ds-lit:#12A594; --ds-mist:#B8DED3;
  --ds-paper:#E6F2EE; --ds-ink:#0E1F1A; --ds-ink-muted:#4E6961; --ds-line:#DDEBE6; --ds-card:#fff;
}
:root{
  --surface-page:var(--ds-paper); --surface-card:var(--ds-card);
  --surface-soft:var(--ds-mist); --text-primary:var(--ds-ink); --text-secondary:var(--ds-ink-muted);
  --text-on-accent:var(--ds-card); --text-on-soft:var(--ds-deep);
  --accent:var(--ds-base); --accent-hover:var(--ds-lit); --accent-soft:var(--ds-mist);
  --border:var(--ds-line); --border-strong:var(--ds-mist);
  --status-warn-bg:#FBF1DE; --status-warn-line:#EBD6A8; --status-warn-ink:#A85B10;
  --status-danger:#B4232A; --status-danger-bg:#FBEBEC;
  --status-ok:#2E9E86; --status-ok-bg:#EBF3EC;
  --mono:ui-monospace,"Cascadia Mono","Segoe UI Mono",Consolas,monospace;
  --sans:"Segoe UI Variable Text","Segoe UI",system-ui,-apple-system,sans-serif;
}
*{box-sizing:border-box}
body{margin:0;background:var(--surface-page);color:var(--text-primary);
     font:15px/1.5 var(--sans);-webkit-font-smoothing:antialiased}
h2{margin:0;text-wrap:balance}
.eyebrow{font:600 11px/1 var(--sans);letter-spacing:.14em;text-transform:uppercase;
         color:var(--text-secondary)}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
.spacer{flex:1 1 auto}

header{position:sticky;top:0;z-index:20;background:linear-gradient(180deg,#fff,var(--surface-page));
       border-bottom:1px solid var(--border);padding:10px 12px}
.bar{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:9px;font-weight:700;letter-spacing:-.01em}
.src{font-size:12.5px;color:var(--text-secondary);display:flex;align-items:center;gap:6px;min-width:0}
.src b{font-weight:600;color:var(--text-primary);font-family:var(--mono);font-size:12px;
       overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:32ch}
.setting{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--text-secondary);
         background:#fff;border:1px solid var(--border);border-radius:8px;padding:5px 9px}
.setting input{width:52px;border:1px solid var(--border);border-radius:5px;padding:2px 5px;
               font:inherit;font-family:var(--mono);text-align:right}
.progress{display:flex;align-items:center;gap:9px;font-size:13px}
.meter{width:104px;height:7px;border-radius:99px;background:var(--surface-soft);overflow:hidden}
.meter i{display:block;height:100%;background:var(--accent);border-radius:99px;
         transition:width .18s ease;width:0}
.btn{font:600 14px/1 var(--sans);border-radius:9px;padding:10px 16px;border:1px solid transparent;
     cursor:pointer;display:inline-flex;align-items:center;gap:7px}
.btn-primary{background:var(--accent);color:var(--text-on-accent)}
.btn-primary:hover:not(:disabled){background:var(--accent-hover)}
/* A disabled Print must read as inert. A tinted fill sits too close to the accent
   and reads as clickable, which on the control gating a clinical print is wrong. */
.btn:disabled{background:#fff;color:var(--text-secondary);cursor:not-allowed;
              border:1px dashed var(--border-strong)}
.btn:disabled svg{opacity:.55}
.why{font-size:12px;color:var(--status-warn-ink);margin-top:5px;text-align:right;max-width:40ch}

main{padding:12px;display:grid;gap:12px;max-width:1500px;margin:0 auto}
.card{background:var(--surface-card);border:1px solid var(--border);border-radius:12px;
      box-shadow:0 1px 2px rgba(16,32,28,.05)}
.notice{padding:13px 15px;border-radius:12px;border:1px solid;display:grid;
        grid-template-columns:auto 1fr;gap:12px;align-items:start}
.notice h2{font-size:14px;margin-bottom:3px}
.notice p{margin:0;font-size:13.5px}
.n-block{background:var(--status-danger-bg);border-color:#F0C7C9;color:#5E1418}
.n-block h2{color:var(--status-danger)}
.n-hand{background:var(--status-warn-bg);border-color:var(--status-warn-line);color:#5C3406}
.n-hand h2{color:var(--status-warn-ink)}
.handlist{margin:9px 0 0;padding:0;list-style:none;display:grid;gap:5px}
.handlist li{display:flex;gap:9px;align-items:baseline;font-size:13px}
.handlist .nm{font-family:var(--mono);font-weight:600}
.handlist .rs{color:#7A4A0C;font-size:12.5px}
.dupe{display:grid;gap:7px;margin-top:9px}
.dupe-row{display:flex;gap:9px;align-items:center;flex-wrap:wrap;background:#fff;
          border:1px solid #F0C7C9;border-radius:8px;padding:7px 10px;font-size:13px}
.dupe-row .nm{font-family:var(--mono);font-weight:600;color:var(--text-primary)}
.dupe-row .sep{color:var(--text-secondary)}
.mini{font:500 12px/1 var(--sans);border:1px solid var(--border);background:#fff;
      border-radius:6px;padding:6px 10px;cursor:pointer;color:var(--text-primary)}
.mini:hover{border-color:var(--accent);color:var(--accent)}

.rowcard{display:grid;grid-template-columns:minmax(280px,1fr) minmax(430px,1.35fr);
         border-radius:12px;overflow:hidden}
.rowcard.done{border-color:var(--accent-soft)}
.rowcard.blocked{border-color:#F0C7C9}
.rowhead{grid-column:1/-1;display:flex;align-items:center;gap:11px;padding:8px 13px;
         border-bottom:1px solid var(--border);background:#FCFDFD}
.rownum{width:23px;height:23px;border-radius:7px;background:var(--surface-soft);
        color:var(--text-on-soft);display:grid;place-items:center;font:700 12px/1 var(--mono);flex:none}
.rowcard.done .rownum{background:var(--accent);color:#fff}
.rowtitle{font-weight:650;font-size:14px;letter-spacing:-.01em}
.flags{display:flex;gap:5px;flex-wrap:wrap}
.pill{font:600 10.5px/1 var(--sans);letter-spacing:.05em;text-transform:uppercase;
      padding:4px 7px;border-radius:5px;border:1px solid}
.p-warn{background:var(--status-warn-bg);border-color:var(--status-warn-line);color:var(--status-warn-ink)}
.p-dang{background:var(--status-danger-bg);border-color:#F0C7C9;color:var(--status-danger)}
.p-soft{background:var(--surface-soft);border-color:var(--border-strong);color:var(--text-on-soft)}

.source{background:#FAFCFB;border-right:1px solid var(--border);min-width:0}
.edit{min-width:0}
/* The two columns answer different questions, so they are told apart by a tinted
   band and a rule rather than by position alone. Kept subtle: this is a clinical
   form, not a dashboard. */
.colhead{display:flex;align-items:center;gap:8px;padding:7px 13px;
         border-bottom:2px solid;font:600 11px/1.4 var(--sans);
         letter-spacing:.13em;text-transform:uppercase}
.colhead svg{flex:none}
.source .colhead{background:#F1F5F4;border-bottom-color:#C9D8D3;color:#4A6159}
.edit .colhead{background:var(--surface-soft);border-bottom-color:var(--accent);
               color:var(--text-on-soft)}
.pad{padding:12px 13px}
.sfield{margin-bottom:9px}
.sfield:last-child{margin-bottom:0}
.slabel{font-size:11px;color:var(--text-secondary);margin-bottom:2px;display:flex;
        align-items:center;gap:6px}
/* Kept from variant B: says at a glance where the chart departs from the source. */
.dot{width:7px;height:7px;border-radius:99px;background:var(--status-ok);flex:none}
.dot.changed{background:var(--status-warn-ink)}
.dot[hidden]{display:none}
.sval{font-family:var(--mono);font-size:12.5px;line-height:1.45;color:var(--text-primary);
      word-break:break-word}
.sval.empty{color:var(--status-danger);font-style:italic}

.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:8px 10px}
.f{display:flex;flex-direction:column;gap:3px;min-width:0}
.f label{font-size:11px;color:var(--text-secondary)}
.f input,.f select{font:14px/1.3 var(--sans);padding:6px 8px;border:1px solid var(--border);
                   border-radius:7px;background:#fff;color:var(--text-primary);width:100%}
.f input:focus,.f select:focus{outline:2px solid var(--accent);outline-offset:-1px;
                               border-color:var(--accent)}
.f input.need{border-color:var(--status-warn-line);background:var(--status-warn-bg)}
.hint{font-size:11px;color:var(--status-warn-ink)}
.c12{grid-column:span 12}.c6{grid-column:span 6}.c4{grid-column:span 4}.c3{grid-column:span 3}
.seg{display:flex;border:1px solid var(--border);border-radius:7px;overflow:hidden;width:fit-content}
.seg button{font:600 12.5px/1 var(--sans);padding:8px 13px;background:#fff;border:0;
            border-right:1px solid var(--border);cursor:pointer;color:var(--text-secondary)}
.seg button:last-child{border-right:0}
.seg button[aria-pressed="true"]{background:var(--accent);color:#fff}
.seg.unset{border-color:var(--status-warn-line)}
.chk{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--text-secondary)}

.rmbtn{font:600 12px/1 var(--sans);border:1px solid var(--border);background:#fff;
        border-radius:7px;padding:6px 10px;cursor:pointer;color:var(--text-secondary);
        display:inline-flex;align-items:center;gap:6px}
.rmbtn:hover{border-color:var(--status-danger);color:var(--status-danger)}
.rowcard.removed{opacity:.62}
.rowcard.removed .source,.rowcard.removed .edit{display:none}
.rowcard.removed .rowhead{border-bottom:0}
.rowcard.removed .rmbtn:hover{border-color:var(--accent);color:var(--accent)}
.confirm{grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;
         gap:12px;padding:9px 13px;border-top:1px solid var(--border);background:#FCFDFD;
         flex-wrap:wrap}
.tick{display:flex;align-items:center;gap:9px;font-size:13.5px;font-weight:600;cursor:pointer}
.tick input{width:19px;height:19px;accent-color:var(--accent);cursor:pointer}
.tick input:disabled{cursor:not-allowed}
.blockmsg{font-size:12.5px;color:var(--status-danger);display:flex;align-items:center;gap:6px;
          text-align:right}
.blockmsg.ok{color:var(--status-ok)}
footer{padding:6px 12px 28px;color:var(--text-secondary);font-size:12px;text-align:center}
/* The one deliberate pause before paper. Kept plain and countable: numbers first,
   then exactly what is being left off, so it can be read in a couple of seconds. */
dialog#confirm{border:0;border-radius:14px;padding:0;max-width:min(620px,92vw);
  box-shadow:0 18px 50px rgba(10,30,25,.28);color:var(--text-primary);
  font:15px/1.5 var(--sans);background:var(--surface-card)}
dialog#confirm::backdrop{background:rgba(10,30,25,.42)}
#confirm .head{padding:16px 20px 12px;border-bottom:2px solid var(--accent);
  background:var(--surface-soft)}
#confirm .head h2{font-size:17px;color:var(--text-on-soft)}
#confirm .head p{margin:4px 0 0;font-size:13px;color:var(--text-on-soft);opacity:.85}
#confirm .body{padding:14px 20px;display:grid;gap:12px;max-height:52vh;overflow:auto}
#confirm .big{display:flex;align-items:baseline;gap:9px}
#confirm .big b{font:700 30px/1 var(--mono);color:var(--accent)}
#confirm section h3{font:600 11px/1 var(--sans);letter-spacing:.13em;text-transform:uppercase;
  color:var(--text-secondary);margin:0 0 5px}
#confirm ul{margin:0;padding-left:18px;font-size:13px;display:grid;gap:2px}
#confirm li{font-family:var(--mono);font-size:12px}
#confirm .warn{background:var(--status-warn-bg);border:1px solid var(--status-warn-line);
  color:#5C3406;border-radius:9px;padding:9px 12px;font-size:13px}
#confirm .foot{padding:12px 20px 16px;display:flex;gap:10px;justify-content:flex-end;
  border-top:1px solid var(--border)}
#toast{position:fixed;left:50%;bottom:20px;transform:translateX(-50%);background:var(--ds-deep);
       color:#fff;padding:11px 17px;border-radius:9px;font-size:13.5px;z-index:50;max-width:70ch}
#toast[hidden]{display:none}
@media (max-width:960px){.rowcard{grid-template-columns:1fr}
  .source{border-right:0;border-bottom:1px solid var(--border)}}

.brand svg.brandmark{color:var(--accent)}
#meter{width:0}
#confirm-cancel{padding:10px 16px}

/* Chart-level fields. One bar, asked once, because they print on every row. */
.chartbar{display:flex;align-items:flex-end;gap:14px;flex-wrap:wrap;padding:11px 14px}
.chartbar .eyebrow{align-self:center}
.cf{display:flex;flex-direction:column;gap:3px;font-size:11px;
    color:var(--text-secondary);min-width:0}
.cf input{font:14px/1.3 var(--sans);padding:7px 9px;border:1px solid var(--border);
          border-radius:7px;background:#fff;color:var(--text-primary);width:26ch}
.cf.narrow input{width:12ch}
.cf input:focus{outline:2px solid var(--accent);outline-offset:-1px;border-color:var(--accent)}
.cf input:placeholder-shown{border-color:var(--status-warn-line);
                            background:var(--status-warn-bg)}
.cfnote{font-size:12px;color:var(--text-secondary);align-self:center}

/* Start screen only. Shares every colour and type token with review.css, which is
   loaded first, so the two screens cannot drift apart. */
.start{max-width:620px;margin:0 auto;padding:56px 20px 40px;display:grid;gap:20px}

.start-brand{display:flex;gap:14px;align-items:flex-start;color:var(--accent)}
.start-brand h1{margin:0;font-size:27px;letter-spacing:-.02em;color:var(--text-primary)}
.start-brand .tagline{margin:5px 0 0;color:var(--text-secondary);font-size:14px;max-width:44ch}

.start-card{padding:22px;display:grid;gap:22px}
.field{display:grid;gap:7px}
.flabel{font-weight:600;font-size:14px}
.field input[type=file]{font:inherit;font-size:13px;padding:11px;background:var(--surface-page);
  border:1px dashed var(--border-strong);border-radius:9px;width:100%}
.field input[type=file]::file-selector-button{font:600 13px/1 var(--sans);margin-right:11px;
  padding:7px 12px;border:1px solid var(--border);border-radius:7px;background:#fff;
  color:var(--text-primary);cursor:pointer}
.field input[type=file]::file-selector-button:hover{border-color:var(--accent);color:var(--accent)}
.inline{display:flex;align-items:center;gap:9px;font-size:14px;color:var(--text-secondary)}
.inline input{width:66px;border:1px solid var(--border);border-radius:6px;padding:6px 8px;
  font:inherit;font-family:var(--mono);text-align:right}
.hint{font-size:12.5px;color:var(--text-secondary);line-height:1.45;margin:0}
.start-card .btn{justify-content:center}

/* A refused file is the one message on this screen that must not be skimmed past. */
.start-error{padding:16px 18px;border-color:var(--status-warn-line);
  background:var(--status-warn-bg);color:var(--status-warn-ink)}
.start-error ul{margin:8px 0 0;padding-left:19px;display:grid;gap:5px;font-size:14px}
.start-error .hint{margin-top:11px;color:inherit;opacity:.9}

.start-foot{text-align:center;font-size:12.5px;color:var(--text-secondary);margin:0}

/* ------------------------------------------------ browser build additions ---- */
/* Layout for the client-rendered review, which uses different markup from the
   Flask template. Tokens and base styles above are shared, so the two builds
   cannot drift apart on colour or type. */

/* Single column stated explicitly: this card picked up a two-track grid from the
   shared stylesheet and put the eyebrow beside the paragraph. */
.notice{padding:15px 18px;background:var(--surface-soft);border-color:var(--border-strong);
  display:block}
.notice p{margin:6px 0 0;font-size:13.5px;color:var(--text-on-soft);line-height:1.5}

.chart-header{padding:16px 18px}
.chart-fields{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:14px;
  margin-top:12px}
.chart-fields input{width:100%;border:1px solid var(--border);border-radius:7px;
  padding:8px 10px;font:inherit}
@media (max-width:640px){.chart-fields{grid-template-columns:1fr}}

.row{padding:14px 16px;display:grid;gap:11px}
.row.is-removed{opacity:.62;background:var(--surface-page)}
.row.is-complete{border-color:var(--status-ok);box-shadow:0 0 0 1px var(--status-ok) inset}
.row-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.rnum{width:25px;height:25px;flex:0 0 auto;display:grid;place-items:center;border-radius:7px;
  background:var(--accent);color:var(--text-on-accent);font-size:12.5px;font-weight:600}
.row-src{display:flex;gap:9px;align-items:baseline;flex-wrap:wrap;min-width:0}
.row-src .nm{font-weight:650}
.row-src .sep,.row-src .gen{font-size:12.5px;color:var(--text-secondary)}
.row-src .gen{font-style:italic}

.flag{font-size:11px;font-weight:600;letter-spacing:.02em;padding:3px 8px;border-radius:99px;
  background:var(--status-warn-bg);color:var(--status-warn-ink);
  border:1px solid var(--status-warn-line);white-space:nowrap}
.flag-variable_dose,.flag-weekly_dosing{background:var(--status-danger-bg);
  color:var(--status-danger);border-color:var(--status-danger)}

.rmbtn{font:600 12px/1 var(--sans);padding:6px 11px;border-radius:7px;cursor:pointer;
  background:#fff;border:1px solid var(--border);color:var(--text-secondary)}
.rmbtn:hover{border-color:var(--status-danger);color:var(--status-danger)}

.note{margin:0;font-size:12.5px;padding:8px 11px;border-radius:8px;
  background:var(--status-warn-bg);color:var(--status-warn-ink);
  border:1px solid var(--status-warn-line)}

.row-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(196px,1fr));gap:12px}
.row-grid .field input[type=text]{width:100%;border:1px solid var(--border);border-radius:7px;
  padding:8px 10px;font:inherit}
.row-grid .field input[type=text]:focus-visible{outline:2px solid var(--accent);
  outline-offset:1px;border-color:var(--accent)}

.kinds{display:flex;gap:7px;flex-wrap:wrap}
.chip{font:600 13px/1 var(--sans);padding:8px 13px;border-radius:99px;cursor:pointer;
  background:#fff;border:1px solid var(--border);color:var(--text-secondary)}
.chip:hover{border-color:var(--accent);color:var(--accent)}
.chip.on{background:var(--accent);border-color:var(--accent);color:var(--text-on-accent)}

.tick{display:flex;gap:8px;align-items:flex-start;font-size:12.5px;
  color:var(--text-secondary);line-height:1.4}
.tick input{margin:1px 0 0;flex:0 0 auto;width:15px;height:15px;accent-color:var(--accent)}

.row-why{margin:0;padding:0;list-style:none;display:grid;gap:4px}
.row-why:empty{display:none}
.row-why li{font-size:12px;color:var(--status-warn-ink)}
.row-why li::before{content:"needs ";opacity:.7}

.dupes{padding:15px 18px}
.dupe-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;padding:10px 0;
  border-top:1px solid var(--border)}
.dupe-row:first-child{border-top:0}
.dupe-med{font-size:12.5px;color:var(--text-secondary);font-family:var(--mono)}
.mini{font:600 12px/1 var(--sans);padding:7px 11px;border-radius:7px;cursor:pointer;
  background:#fff;border:1px solid var(--border);color:var(--text-primary)}
.mini:hover{border-color:var(--accent);color:var(--accent)}

.handwrite{padding:15px 18px}
.handwrite ul{margin:10px 0 0;padding:0;list-style:none;display:grid;gap:8px}
.handwrite li{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;font-size:13.5px}

/* The print button is the one control that must never read as available when it is
   not. Inherits the dashed inert style from .btn:disabled above. */
#print-why{white-space:normal}

@media print{
  header,.rmbtn,.mini,.chip,#restart-btn,.notice{display:none !important}
}

/* A class that sets `display` beats the `hidden` attribute's user-agent rule, so
   `el.hidden = true` silently did nothing to the start screen (.start is display:grid)
   and both screens rendered on top of each other. Every test passed; only opening the
   page showed it. Keep this rule last. */
/* The print blocker is the most important sentence in the header. Give it the width
   to be read as one line of prose, not a narrow ragged column. */
header .why{margin:6px 0 0 auto;text-align:right;max-width:min(78ch,100%)}

[hidden]{display:none !important}
