/* Winterfield Health — portal stylesheet
   The clinical workspace and MyWinterfield, behind portal/.

   Shares the brand tokens with site.css but deliberately does not share its
   layout. The public site is a marketing page: generous whitespace, rounded
   pills, serif headings at display sizes. This is a workstation. It is denser,
   squarer, and information-first, because a clinician scanning a chart and a
   visitor reading a hero are not doing the same job. Keeping the palette makes
   it recognizably Winterfield; keeping the marketing layout would have made it
   unusable.

   Deliberately a separate file rather than an addition to site.css or
   pages.css: nothing on the public site needs any of this, and the public pages
   should not carry the weight. See PLAT-13 for the wider two-stylesheet
   question, which this does not change. */

:root {
  --wf-terracotta: #B4552D;
  --wf-terracotta-hover: #8F3F1F;
  --wf-olive: #4A5D43;
  --wf-gold: #E9A13B;
  --wf-ink: #3B2E25;
  --wf-cream: #FAF5EF;
  --wf-body: #5C4F44;
  --wf-muted: #8A7A6C;
  --wf-on-terracotta: #FFF7F0;
  --wf-hairline: rgba(59, 46, 37, .12);
  --wf-hairline-strong: rgba(59, 46, 37, .2);
  --wf-tint: #F5EDE2;

  --wf-serif: 'Lora', Georgia, serif;
  --wf-sans: 'Nunito Sans', system-ui, -apple-system, sans-serif;
  --wf-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  /* Clinical status colors. Chosen to sit beside terracotta without competing,
     and to stay legible for the roughly 8 percent of men with red-green color
     deficiency: the high/low flags carry an arrow glyph as well as a color, so
     color is never the only signal. */
  --wf-abnormal: #A8341F;
  --wf-abnormal-bg: #FBEDE9;
  --wf-normal: #4A5D43;
  --wf-caution: #8A5A12;
  --wf-caution-bg: #FCF3E2;

  --wf-panel: #FFFFFF;
  --wf-shell: #F3EBE1;

  --wf-portal-max: 1480px;
}

*, *::before, *::after { box-sizing: border-box; }

body.portal {
  margin: 0;
  background: var(--wf-shell);
  color: var(--wf-ink);
  font: 400 15px/1.55 var(--wf-sans);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

a { color: var(--wf-terracotta); }
a:hover { color: var(--wf-terracotta-hover); }

h1, h2, h3, h4 { font-family: var(--wf-serif); font-weight: 600; margin: 0; }

.portal-wrap {
  max-width: var(--wf-portal-max);
  margin: 0 auto;
  padding: 0 28px;
  width: 100%;
}
.portal-narrow { max-width: 720px; }

.kicker {
  font: 700 11px var(--wf-sans);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--wf-muted);
  margin: 0 0 6px;
}

/* ---------- the synthetic-data banner ----------
   Present on every portal page and not dismissible. A demo EMR that looks
   convincing is the goal, so the one thing that must never be ambiguous is
   whether the data is real. */

.demo-banner {
  background: var(--wf-olive);
  color: #F2F5EF;
  font: 700 12px var(--wf-sans);
  letter-spacing: .04em;
  text-align: center;
  padding: 7px 16px;
}

/* ---------- header ---------- */

.portal-header {
  background: var(--wf-panel);
  border-bottom: 1px solid var(--wf-hairline);
  position: sticky;
  top: 0;
  z-index: 40;
}
.portal-header .portal-wrap {
  display: flex;
  align-items: center;
  gap: 20px;
  min-height: 58px;
}
.portal-lockup {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--wf-ink);
}
.portal-lockup .word {
  font: 600 17px var(--wf-serif);
  letter-spacing: -.01em;
}
.portal-lockup .word em { font-style: normal; color: var(--wf-terracotta); }

.portal-context {
  font: 700 11px var(--wf-sans);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--wf-muted);
  padding-left: 20px;
  border-left: 1px solid var(--wf-hairline);
}

.portal-user {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 16px;
}
.portal-who { text-align: right; line-height: 1.25; }
.portal-who strong { display: block; font-size: 14px; }
.portal-role { font-size: 12px; color: var(--wf-muted); }
.portal-signout {
  font: 700 13px var(--wf-sans);
  text-decoration: none;
  border: 1px solid var(--wf-hairline-strong);
  border-radius: 4px;
  padding: 7px 13px;
  color: var(--wf-body);
}
.portal-signout:hover {
  background: var(--wf-tint);
  color: var(--wf-ink);
}

/* ---------- buttons ---------- */

.btn {
  display: inline-block;
  font: 700 13.5px var(--wf-sans);
  border-radius: 4px;
  padding: 10px 18px;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background .13s, color .13s, border-color .13s;
}
.btn-primary { background: var(--wf-terracotta); color: var(--wf-on-terracotta); }
.btn-primary:hover { background: var(--wf-terracotta-hover); color: var(--wf-on-terracotta); }
.btn-quiet {
  background: transparent;
  border-color: var(--wf-hairline-strong);
  color: var(--wf-body);
}
.btn-quiet:hover { background: var(--wf-tint); color: var(--wf-ink); }
.btn-sm { font-size: 12.5px; padding: 7px 13px; }

/* ---------- panels ---------- */

.panel {
  background: var(--wf-panel);
  border: 1px solid var(--wf-hairline);
  border-radius: 6px;
  padding: 22px 24px;
}
.panel > h2, .panel > h3 {
  font-size: 16px;
  margin-bottom: 14px;
}
.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 14px;
}
.panel-head h2, .panel-head h3 { font-size: 16px; margin: 0; }
.panel-count { font-size: 12.5px; color: var(--wf-muted); }

/* A panel that folds. The <summary> is the panel head, so an open fold is
   indistinguishable from every other panel except for the caret. Native
   <details> rather than a JS toggle: it folds with JavaScript off, it is a
   real disclosure widget to a screen reader without any ARIA, and Find in
   Page opens it on its own in browsers that support that. */
.panel-fold > summary.panel-head {
  cursor: pointer;
  align-items: center;
  list-style: none;
}
.panel-fold > summary.panel-head::-webkit-details-marker { display: none; }
.panel-fold > summary.panel-head h2 {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}
/* Caret drawn from two borders rather than a glyph: it rotates cleanly and
   needs no font that may not have loaded yet. Points right when closed and
   down when open. */
.panel-fold > summary.panel-head h2::before {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 2px solid var(--wf-muted);
  border-bottom: 2px solid var(--wf-muted);
  transform: rotate(-45deg);
  transition: transform .13s;
}
.panel-fold[open] > summary.panel-head h2::before { transform: rotate(45deg); }
.panel-fold > summary.panel-head:hover h2,
.panel-fold > summary.panel-head:hover h2::before { color: var(--wf-terracotta); }
.panel-fold > summary.panel-head:hover h2::before { border-color: var(--wf-terracotta); }
.panel-fold > summary.panel-head:focus-visible {
  outline: 2px solid var(--wf-terracotta);
  outline-offset: 3px;
  border-radius: 3px;
}
/* A closed fold has nothing under the head, so the head's own bottom margin
   leaves a band of empty panel. */
.panel-fold:not([open]) > summary.panel-head { margin-bottom: 0; }

/* ---------- login ---------- */

.login-page { padding: 34px 28px 60px; }
.login-intro { margin-bottom: 20px; }
.login-intro h1 { font-size: 30px; }
.login-sub { color: var(--wf-body); margin: 6px 0 0; }

.login-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--wf-hairline);
  margin-bottom: 24px;
}
.login-tab {
  font: 700 13.5px var(--wf-sans);
  text-decoration: none;
  color: var(--wf-muted);
  padding: 11px 18px;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: 5px 5px 0 0;
  margin-bottom: -1px;
}
.login-tab:hover { color: var(--wf-ink); background: rgba(255, 255, 255, .6); }
.login-tab.is-on {
  background: var(--wf-panel);
  border-color: var(--wf-hairline);
  color: var(--wf-terracotta);
}

.login-grid {
  display: grid;
  grid-template-columns: minmax(300px, 360px) 1fr;
  gap: 24px;
  align-items: start;
}

.login-form { display: flex; flex-direction: column; }
.login-form label {
  font: 700 12px var(--wf-sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--wf-muted);
  margin-bottom: 5px;
}
.login-form input {
  font: 400 15px var(--wf-sans);
  padding: 10px 12px;
  border: 1px solid var(--wf-hairline-strong);
  border-radius: 4px;
  background: #FFF;
  color: var(--wf-ink);
  margin-bottom: 16px;
}
.login-form input:focus {
  outline: 2px solid var(--wf-terracotta);
  outline-offset: 1px;
  border-color: var(--wf-terracotta);
}
.login-form button { margin-top: 4px; }

.form-error {
  background: var(--wf-abnormal-bg);
  border-left: 3px solid var(--wf-abnormal);
  color: var(--wf-abnormal);
  font-size: 13.5px;
  font-weight: 600;
  padding: 10px 12px;
  margin: 0 0 16px;
}
.login-note {
  font-size: 12.5px;
  color: var(--wf-muted);
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--wf-hairline);
}

.login-accounts h2 { font-size: 16px; }
.login-accounts-sub { font-size: 13px; color: var(--wf-muted); margin: 5px 0 14px; }
.login-accounts-foot {
  font-size: 12.5px;
  color: var(--wf-muted);
  margin: 14px 0 0;
}

.account-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 10px;
}

/* The account card is a button so it is keyboard reachable and the hint can be
   shown on focus as well as hover. */
.account-card {
  position: relative;
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  background: var(--wf-panel);
  border: 1px solid var(--wf-hairline);
  border-radius: 6px;
  padding: 13px 15px;
  cursor: pointer;
  transition: border-color .13s, box-shadow .13s;
}
.account-card:hover,
.account-card:focus-visible {
  border-color: var(--wf-terracotta);
  box-shadow: 0 1px 0 var(--wf-terracotta);
  outline: none;
}
.account-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.account-name { font: 700 14.5px var(--wf-sans); }
.account-tag {
  font: 700 10px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-muted);
  white-space: nowrap;
}
.account-sub {
  display: block;
  font-size: 12.5px;
  color: var(--wf-body);
  margin-top: 3px;
}

/* The hover-help. Carries the credentials and the showcase note. */
.account-hint {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  z-index: 30;
  display: none;
  background: var(--wf-ink);
  color: #FAF5EF;
  border-radius: 6px;
  padding: 12px 14px;
  font-size: 12.5px;
  line-height: 1.5;
  box-shadow: 0 8px 24px rgba(59, 46, 37, .28);
}
.account-card:hover .account-hint,
.account-card:focus-visible .account-hint { display: block; }

/* Wraps because the passwords are 16 to 19 random characters as of 2026-07-30
   and a username and a password no longer sit side by side in a 320px card. */
.hint-creds { display: flex; flex-wrap: wrap; gap: 6px 8px; margin-bottom: 7px; }
.hint-creds code {
  word-break: break-all;
  font: 700 12.5px var(--wf-mono);
  background: rgba(250, 245, 239, .14);
  border: 1px solid rgba(250, 245, 239, .22);
  border-radius: 3px;
  padding: 3px 7px;
  color: #FFF;
}
.hint-showcase { display: block; color: #E4D8CB; }
.hint-fill {
  display: block;
  margin-top: 8px;
  font: 700 10.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-gold);
}

/* Confirmation that a click landed, since the form is off to the side. */
.account-card.just-filled {
  border-color: var(--wf-olive);
  box-shadow: 0 1px 0 var(--wf-olive);
}

/* ---------- the sign-out notice ---------- */

/* Replaced the wrong-side interstitial on 2026-07-30. Crossing between the two
   sides signs the current identity out and says so here, rather than stopping
   on a page to ask. Bottom right, because the top of every portal page already
   carries the demo banner and the header.

   It takes itself away with a delayed animation rather than a timer, so it
   still clears on a page with scripting off. `visibility` is animated as well
   as `opacity` so the finished toast stops swallowing clicks aimed at whatever
   is underneath it. */
.portal-toast {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 200;
  max-width: 330px;
  background: var(--wf-ink);
  color: #FAF5EF;
  border-left: 3px solid var(--wf-gold);
  border-radius: 6px;
  padding: 12px 15px;
  box-shadow: 0 10px 30px rgba(59, 46, 37, .3);
  cursor: pointer;
  animation: wf-toast-in .2s ease-out both,
             wf-toast-out .45s ease-in 5.6s both;
}
.toast-text {
  display: block;
  font: 700 13.5px var(--wf-sans);
}
.toast-note {
  display: block;
  margin-top: 3px;
  font-size: 12.5px;
  line-height: 1.45;
  color: #E4D8CB;
}

@keyframes wf-toast-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes wf-toast-out {
  from { opacity: 1; visibility: visible; }
  to   { opacity: 0; visibility: hidden; }
}

/* No slide, and no fade worth the name, but it must still go away. */
@media (prefers-reduced-motion: reduce) {
  .portal-toast { animation: wf-toast-out .01s linear 6s both; }
}

@media (max-width: 560px) {
  .portal-toast { right: 12px; left: 12px; bottom: 12px; max-width: none; }
}

/* ---------- provider landing ---------- */

.landing { padding: 30px 28px 60px; }
.landing-head { margin-bottom: 26px; }
.landing-head h1 { font-size: 27px; }
.landing-head p { color: var(--wf-body); margin: 7px 0 0; max-width: 70ch; }

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 26px;
}
.stat {
  background: var(--wf-panel);
  border: 1px solid var(--wf-hairline);
  border-radius: 6px;
  padding: 15px 17px;
}
.stat-value {
  font: 600 25px var(--wf-serif);
  display: block;
  line-height: 1.15;
}
.stat-label {
  font: 700 10.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-muted);
  display: block;
  margin-top: 4px;
}

.op-section { margin-bottom: 30px; }
.op-section > h2 {
  font-size: 13px;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-family: var(--wf-sans);
  font-weight: 700;
  color: var(--wf-muted);
  margin-bottom: 12px;
}
.op-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(285px, 1fr));
  gap: 12px;
}
.op-card {
  display: block;
  background: var(--wf-panel);
  border: 1px solid var(--wf-hairline);
  border-radius: 6px;
  padding: 17px 19px;
  text-decoration: none;
  color: inherit;
  transition: border-color .13s, transform .13s;
}
.op-card:hover {
  border-color: var(--wf-terracotta);
  transform: translateY(-1px);
  color: inherit;
}
.op-card h3 { font-size: 15.5px; }
.op-card p {
  font-size: 12.5px;
  color: var(--wf-body);
  margin: 5px 0 0;
}
.op-card.is-stub { opacity: .62; }
.op-card.is-stub:hover { border-color: var(--wf-hairline-strong); transform: none; }
.op-badge {
  display: inline-block;
  font: 700 9.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  background: var(--wf-caution-bg);
  color: var(--wf-caution);
  border-radius: 3px;
  padding: 2px 6px;
  margin-left: 7px;
  vertical-align: 2px;
}

/* ---------- patient search workspace ---------- */

.work-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 24px 28px 16px;
  max-width: var(--wf-portal-max);
  margin: 0 auto;
  width: 100%;
}
.work-head h1 { font-size: 23px; }
.work-head .crumb {
  font-size: 12.5px;
  color: var(--wf-muted);
}
.work-head .crumb a { text-decoration: none; }
.work-head .crumb a:hover { text-decoration: underline; }

.work-grid {
  display: grid;
  grid-template-columns: 340px 1fr;
  gap: 20px;
  align-items: start;
  padding: 0 28px 60px;
  max-width: var(--wf-portal-max);
  margin: 0 auto;
  width: 100%;
}

.search-panel { position: sticky; top: 76px; }
.search-form { display: grid; gap: 11px; }
.search-form .field { display: flex; flex-direction: column; }
.search-form label {
  font: 700 11px var(--wf-sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--wf-muted);
  margin-bottom: 4px;
}
.search-form input {
  font: 400 14.5px var(--wf-sans);
  padding: 9px 11px;
  border: 1px solid var(--wf-hairline-strong);
  border-radius: 4px;
  background: #FFF;
  color: var(--wf-ink);
}
.search-form input:focus {
  outline: 2px solid var(--wf-terracotta);
  outline-offset: 1px;
  border-color: var(--wf-terracotta);
}
.search-form .field-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.search-hint { font-size: 12px; color: var(--wf-muted); margin: 0; }
.search-actions { display: flex; gap: 8px; align-items: center; }

.search-status {
  font: 700 11px var(--wf-sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--wf-muted);
  margin: 16px 0 8px;
  padding-top: 14px;
  border-top: 1px solid var(--wf-hairline);
}

.result-list { list-style: none; margin: 0; padding: 0; }
.result-list li + li { border-top: 1px solid var(--wf-hairline); }
.result {
  display: block;
  padding: 10px 2px;
  text-decoration: none;
  color: inherit;
}
.result:hover { background: var(--wf-tint); color: inherit; }
.result-name { font: 700 14px var(--wf-sans); display: block; }
.result-meta { font-size: 12px; color: var(--wf-muted); display: block; margin-top: 2px; }
.result mark {
  background: rgba(233, 161, 59, .34);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}
.result-empty { font-size: 13px; color: var(--wf-muted); padding: 8px 0; }

/* ---------- tables ---------- */

.table-scroll { overflow-x: auto; }

/* A long table cut to five rows, with a button for the rest.
   Deliberately not a scroll box, which is what this was until 2026-07-30.4.
   A scrollable region in the middle of a long page swallows the wheel: the
   pointer crosses it on the way down the chart, the page stops moving and the
   box starts, and the reader has to go around it. Cutting the rows costs one
   click and steals nothing. */
.table-short tbody tr:nth-child(n+6) { display: none; }
.table-short.is-expanded tbody tr { display: table-row; }
/* The row hover already reads as "this is clickable". portal.js makes it so;
   this says so. The Open link inside it stays the real control. */
.table-short tbody tr { cursor: pointer; }

/* Name on its line, MRN under it. Side by side, the pair wrapped mid-name on
   almost every row of every patient list, and those rows are two lines tall
   anyway. */
.mrn-line { display: block; margin-top: 1px; }
/* Enough width for a three-part name on one line before the column gives up
   and wraps it. Auto table layout will still take the column narrower than
   this on a small screen, which is the right outcome there. */
.patient-cell { min-width: 190px; }

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
table.data th {
  text-align: left;
  font: 700 10.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-muted);
  padding: 0 12px 8px 0;
  border-bottom: 1px solid var(--wf-hairline-strong);
  white-space: nowrap;
}
table.data td {
  padding: 9px 12px 9px 0;
  border-bottom: 1px solid var(--wf-hairline);
  vertical-align: top;
}
table.data tbody tr:hover { background: var(--wf-tint); }
table.data tr.is-target { background: rgba(233, 161, 59, .18); }
table.data td.num { text-align: right; padding-right: 16px; font-variant-numeric: tabular-nums; }
table.data td.nowrap, table.data th.nowrap { white-space: nowrap; }
table.data a { text-decoration: none; font-weight: 600; }
table.data a:hover { text-decoration: underline; }
.t-date { font-variant-numeric: tabular-nums; white-space: nowrap; }
.t-quiet { color: var(--wf-muted); }
.t-code {
  font: 400 11.5px var(--wf-mono);
  color: var(--wf-muted);
}

/* ---------- clinical flags and pills ---------- */

.pill {
  display: inline-block;
  font: 700 10px var(--wf-sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  border-radius: 3px;
  padding: 2px 7px;
  white-space: nowrap;
}
.pill-amb { background: var(--wf-tint); color: var(--wf-body); }
.pill-imp { background: var(--wf-abnormal-bg); color: var(--wf-abnormal); }
.pill-emer { background: #F6E2DC; color: #8C2A16; }
.pill-active { background: #E8EDE4; color: var(--wf-normal); }
.pill-resolved { background: var(--wf-tint); color: var(--wf-muted); }
/* Booked, not happened. Gold rather than terracotta: the brand's forward-looking
   accent, and it does not read as an alert the way the abnormal reds do. */
.pill-scheduled {
  background: #FBEEDA;
  color: #8A5A11;
  text-transform: none;
  letter-spacing: .02em;
  font-size: 10.5px;
}

.flag { font-weight: 700; white-space: nowrap; }
.flag-high { color: var(--wf-abnormal); }
.flag-low { color: var(--wf-abnormal); }
.flag::after {
  font-size: 11px;
  margin-left: 3px;
}
.flag-high::after { content: "\2191 H"; }
.flag-low::after { content: "\2193 L"; }

/* ---------- patient chart ---------- */

/* The patient banner and the section nav pin together, under the portal header.
   One sticky wrapper, not two sticky children: they were previously both
   sticky at top: 58px, so the nav came to rest in the same place as the banner
   and, having the lower z-index, slid underneath it and disappeared. Sticking
   the nav below the banner instead would mean hardcoding the banner's height,
   which is not a constant, because .chart-facts wraps to a second row on a
   narrow window. The wrapper does the arithmetic for free. */
.chart-sticky {
  position: sticky;
  top: 58px;
  z-index: 30;
}

.chart-banner {
  background: var(--wf-panel);
  border-bottom: 1px solid var(--wf-hairline);
}
.chart-banner .portal-wrap {
  display: flex;
  align-items: center;
  gap: 26px;
  flex-wrap: wrap;
  padding-top: 15px;
  padding-bottom: 15px;
}
.chart-id h1 { font-size: 22px; line-height: 1.2; }

/* Rendered only while a visit is focused, in place of the plain h1. Two lines
   inside one outlined box: a small terracotta label saying where the link
   goes, and the patient name at heading size. The name keeps the ink color
   rather than taking the link terracotta, so the banner still reads as a
   patient banner first and a control second. */
.chart-name-return { font-size: 22px; line-height: 1.2; }
.chart-name-return a {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  text-decoration: none;
  border: 1px solid var(--wf-hairline-strong);
  border-radius: 5px;
  padding: 5px 13px 7px;
  transition: background .13s, border-color .13s;
}
.chart-name-return a:hover {
  background: var(--wf-tint);
  border-color: var(--wf-terracotta);
}
.chart-name-return a:focus-visible {
  outline: 2px solid var(--wf-terracotta);
  outline-offset: 1px;
}
.chart-return-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: 700 9.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-terracotta);
}
.chart-name-return a:hover .chart-return-label { color: var(--wf-terracotta-hover); }
.chart-return-label svg { flex: none; }
.chart-return-name { color: var(--wf-ink); }

.chart-id .chart-sub {
  font-size: 12.5px;
  color: var(--wf-muted);
  margin-top: 3px;
}
.chart-facts {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  margin-left: auto;
}
.chart-fact { line-height: 1.3; }
.chart-fact .k {
  display: block;
  font: 700 9.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-muted);
}
.chart-fact .v { font-size: 13.5px; font-weight: 600; }

.chart-nav {
  background: var(--wf-shell);
  border-bottom: 1px solid var(--wf-hairline);
}
.chart-nav .portal-wrap {
  display: flex;
  gap: 3px;
  overflow-x: auto;
  padding-top: 7px;
  padding-bottom: 7px;
}
.chart-nav a {
  font: 700 12px var(--wf-sans);
  text-decoration: none;
  color: var(--wf-body);
  padding: 6px 11px;
  border-radius: 4px;
  white-space: nowrap;
}
.chart-nav a:hover { background: var(--wf-panel); color: var(--wf-ink); }

.chart-body {
  padding: 22px 28px 70px;
  max-width: var(--wf-portal-max);
  margin: 0 auto;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 18px;
  align-items: start;
}
.col-6 { grid-column: span 6; }
.col-12 { grid-column: span 12; }

/* Anchor targets sit under three pinned bars, the portal header, the patient
   banner and the section nav, so a jump to #labs has to stop short of #labs or
   the bars cover the heading it just jumped to. --wf-chart-chrome is the height
   of all three, measured and set by portal.js because it depends on whether the
   banner facts have wrapped. The fallback is the measured height with nothing
   wrapped: 59 header, 92 banner, 42 nav, on 2026-07-29. */
.chart-body > section {
  scroll-margin-top: calc(var(--wf-chart-chrome, 193px) + 14px);
}

.kv { margin: 0; font-size: 13.5px; }
.kv div {
  display: grid;
  grid-template-columns: 128px 1fr;
  gap: 10px;
  padding: 5px 0;
}
.kv div + div { border-top: 1px solid var(--wf-hairline); }
.kv dt { color: var(--wf-muted); font-size: 12.5px; }
.kv dd { margin: 0; }

.stack { list-style: none; margin: 0; padding: 0; font-size: 13.5px; }
.stack li { padding: 8px 0; }
.stack li + li { border-top: 1px solid var(--wf-hairline); }
.stack .line1 { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.stack .title { font-weight: 600; }
.stack .line2 { font-size: 12.5px; color: var(--wf-muted); margin-top: 2px; }

.empty-note {
  font-size: 13px;
  color: var(--wf-muted);
  font-style: italic;
  margin: 0;
}

/* ---------- code explanations ---------- */

/* A code that can explain itself. Dotted underline rather than a link color:
   it is not navigation, and the chart already has enough terracotta in it. */
/* Never broken across lines. A code is one token to read even though it has a
   hyphen in the middle, and a browser will happily break "13457-7" after the
   hyphen when the column is tight. */
.code-chip {
  cursor: help;
  white-space: nowrap;
  border-bottom: 1px dotted var(--wf-hairline-strong);
}
.code-chip:hover { color: var(--wf-body); border-bottom-color: var(--wf-terracotta); }
.code-chip:focus-visible {
  outline: 2px solid var(--wf-terracotta);
  outline-offset: 2px;
  border-radius: 2px;
}

.code-pop {
  position: fixed;
  z-index: 60;               /* above the pinned banner and nav, below dialogs */
  width: min(330px, calc(100vw - 24px));
  background: var(--wf-panel);
  border: 1px solid var(--wf-hairline-strong);
  border-radius: 6px;
  box-shadow: 0 14px 34px rgba(59, 46, 37, .22);
  padding: 12px 14px;
  font: 400 13px/1.5 var(--wf-sans);
  color: var(--wf-ink);
}
.code-pop[hidden] { display: none; }
.code-pop-head {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin: 0 0 5px;
}
.code-pop-system {
  font: 700 9.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-muted);
}
.code-pop-code { font: 400 12px var(--wf-mono); color: var(--wf-body); }
.code-pop-title { margin: 0; font-weight: 600; }
.code-pop-detail { margin: 5px 0 0; font-size: 12.5px; color: var(--wf-body); }
.code-pop-ours {
  margin: 6px 0 0;
  font-size: 12.5px;
  color: var(--wf-body);
  border-left: 2px solid var(--wf-gold);
  padding-left: 8px;
}
.code-pop-source {
  margin: 9px 0 0;
  padding-top: 8px;
  border-top: 1px solid var(--wf-hairline);
  font-size: 11px;
  line-height: 1.45;
  color: var(--wf-muted);
}

/* ---------- provider notes ---------- */

/* The note as filed: fixed sections, and its own line breaks. Wrapped rather
   than scrolled sideways, because a clinical note read in a 70-character
   window with a horizontal scrollbar is not read. */
.note-text {
  font: 400 12.5px/1.65 var(--wf-mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  margin: 0;
  color: var(--wf-ink);
  background: var(--wf-tint);
  border-radius: 5px;
  padding: 16px 18px;
}
.visit-note-head { font-size: 14px; margin: 20px 0 4px; }
.visit-note-meta {
  font-size: 12.5px;
  color: var(--wf-muted);
  margin: 0 0 10px;
}
.note-loading { color: var(--wf-muted); font-size: 13.5px; margin: 0; }

/* Two controls in one table cell, and the cell is the narrowest column. */
.row-actions {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.btn-note { padding: 3px 9px; font-size: 11.5px; }

/* The note pop-over takes the summary panel's construction wholesale, class
   `previsit` and all, and only narrows it: a note is a column of text about
   70 characters wide and does not need 860px. */
/* Both classes in the selector on purpose: `dialog.previsit` sets the width
   further down this file, and at equal specificity the later rule would win. */
dialog.previsit.notedoc { width: min(760px, 94vw); }
dialog.notedoc .previsit-body { padding: 18px 22px; }

/* ---------- scheduled visits ---------- */

.upcoming-item { padding: 12px 0; }
.upcoming-item:first-child { padding-top: 2px; }
.upcoming-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 9px;
}
/* Nothing else in the chart puts a button inside a list row, and the row's own
   13.5px would otherwise win over the button's font shorthand. */
.upcoming-actions .btn { line-height: 1.2; }

/* The focused-visit panel when the visit is still ahead. Gold left edge, the
   same signal the Scheduled pill carries, so a planned visit does not read as
   a record of something that happened. */
.panel-planned { border-left: 3px solid var(--wf-gold); }
.planned-note {
  font-size: 13px;
  color: var(--wf-body);
  margin: 0 0 14px;
}

.vitals-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
  gap: 10px;
}
/* A column, so the graph can be pushed to the bottom of the tile. Grid items
   stretch to the tallest tile in their row, so bottom-aligning the graphs
   lines them all up across the row however many lines each label takes:
   "Respiratory rate" wraps to two and "Weight" does not, and before this the
   graph under the two-line label sat 15px lower than its neighbors. */
.vital {
  display: flex;
  flex-direction: column;
  background: var(--wf-tint);
  border-radius: 5px;
  padding: 10px 12px;
}
/* Value and unit are one line inside the column, not two flex items. */
.vital-value {
  display: block;
  margin-top: 1px;
}
.vital .k {
  display: block;
  font: 700 9.5px var(--wf-sans);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--wf-muted);
}
.vital .v { font: 600 18px var(--wf-serif); }
.vital .u { font-size: 11px; color: var(--wf-muted); }

/* margin-top:auto, not a fixed gap: it takes up whatever slack the tile has
   and puts the graph on the floor. */
.trend {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  /* 34 of bars plus the 8 of breathing room above them: box-sizing is
     border-box here, so the padding has to be inside the number or the bars
     lose 8px of height and stop matching the line graphs beside them. */
  height: 42px;
  margin-top: auto;
  padding-top: 8px;
}
.trend i {
  flex: 1;
  background: var(--wf-terracotta);
  opacity: .5;
  border-radius: 1px 1px 0 0;
  min-height: 2px;
}
.trend i:last-child { opacity: 1; }

/* Weight and BMI. Same box and same 34px height as the bars so a grid of
   mixed tiles still lines up; only the mark inside changes. */
.trend-line { display: block; height: auto; }
.trend-line svg {
  display: block;
  width: 100%;
  height: 34px;
  overflow: visible;
}
.trend-line polyline {
  fill: none;
  stroke: var(--wf-terracotta);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.trend-line circle { fill: var(--wf-terracotta); }

.section-more { margin-top: 12px; font-size: 12.5px; }

/* ---------- pre-visit summary ----------
   The button lives in the pinned patient banner, so it stays reachable from
   anywhere in a long chart, and the panel it opens is a native <dialog>. Native
   rather than a hand-rolled overlay for three things that are tedious and easy
   to get wrong by hand: the focus trap, Esc to close, and rendering above every
   other stacking context on the page, including the two pinned bars. */

/* Last child of the banner's flex row. .chart-facts carries the margin-left:auto
   that pushes both of them right, so this needs no margin of its own. */
.chart-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.btn-previsit {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}
.btn-previsit svg { flex: none; }

/* The height is definite rather than left to the content, and that is a fix
   rather than a preference. It is the same fix `.diag-dialog` carries in
   diagnostics.css and it is here for the same reason.

   With `height: auto` the body below is a flex item of `flex: 1 1 0%`. A zero
   basis contributes nothing to the container's intrinsic height, so the dialog
   has only the head and the foot to size itself from. Some browsers ignore that
   and size the container from the item's max-content contribution anyway, and
   some follow it and collapse the panel to its header. That split is the whole
   bug: Dave saw the diagnostics version collapse on Mac Safari on 2026-07-30
   while the same page was correct on Windows, and reported this panel behaving
   the same way on 2026-07-30.3. A definite height gives the flex layout a real
   number to distribute and takes the guess away.

   This was predicted before it was reported. Session 2026-07-30.1 recorded that
   this dialog shared the construction and had not been seen to misbehave. It
   had; nobody had opened it in Safari. */
dialog.previsit {
  width: min(860px, 94vw);
  max-width: none;
  height: min(88vh, 900px);
  max-height: 88vh;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: var(--wf-panel);
  color: var(--wf-ink);
  font: 400 15px/1.55 var(--wf-sans);
  box-shadow: 0 24px 70px rgba(59, 46, 37, .34);
  overflow: hidden;
}

/* The display belongs on [open] and nowhere else.
   Browsers hide a closed dialog with `dialog:not([open]) { display: none }` in
   their own stylesheet. That has the same specificity as `dialog.previsit`, and
   an author stylesheet beats the browser's at equal specificity, so putting
   `display: flex` on the element itself overrode it and the closed panel stayed
   displayed. It then took the browser's `position: absolute; margin: auto` for
   dialogs and settled at the top of the page, half behind the header, where Dave
   found it on 2026-07-29.

   Column, so the head and foot hold still and only the summary scrolls: a long
   summary in a panel that scrolls as one block loses its own close button off
   the top. */
dialog.previsit[open] {
  display: flex;
  flex-direction: column;
}
dialog.previsit::backdrop {
  background: rgba(43, 33, 26, .52);
  backdrop-filter: blur(2px);
}

dialog.previsit[open] { animation: previsit-in .16s ease-out; }
@keyframes previsit-in {
  from { opacity: 0; transform: translateY(8px) scale(.99); }
  to   { opacity: 1; transform: none; }
}

.previsit-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 18px 22px 15px;
  border-bottom: 1px solid var(--wf-hairline);
}
.previsit-head .kicker { margin-bottom: 3px; }
.previsit-head h2 { font-size: 20px; line-height: 1.2; }
.previsit-sub {
  font-size: 12.5px;
  color: var(--wf-muted);
  margin: 4px 0 0;
}

/* Deliberately labeled as well as an X. The panel can be holding a minute of
   work and the way out of it should not be a guess. */
.previsit-close {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: none;
  font: 700 12.5px var(--wf-sans);
  color: var(--wf-body);
  background: transparent;
  border: 1px solid var(--wf-hairline-strong);
  border-radius: 4px;
  padding: 7px 12px;
  cursor: pointer;
  transition: background .13s, color .13s, border-color .13s;
}
.previsit-close:hover {
  background: var(--wf-abnormal-bg);
  border-color: var(--wf-abnormal);
  color: var(--wf-abnormal);
}
.previsit-close .x { font-size: 17px; line-height: 1; margin-top: -1px; }

/* `flex: 1 1 auto` rather than `flex: 1`, which is `flex: 1 1 0%`. The basis is
   the half of the fix that lives on the item: with a zero basis this box tells
   its parent it needs no room at all, which is what let the panel collapse.

   min-height: 0 is what lets a flex item scroll instead of growing past its
   parent. Without it the item's automatic minimum is its content size and the
   overflow never engages, so a long summary would push the foot off the bottom
   instead of scrolling under it. */
.previsit-body {
  overflow-y: auto;
  padding: 20px 24px 24px;
  flex: 1 1 auto;
  min-height: 0;
}
.previsit-body:focus { outline: none; }

.previsit-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 12px 22px;
  border-top: 1px solid var(--wf-hairline);
  background: var(--wf-tint);
}
.previsit-actions { display: flex; gap: 8px; flex-wrap: wrap; }
/* `display: flex` above is an author rule and beats the browser's own
   `[hidden] { display: none }`, so every dialog that ships its action bar hidden
   and unhides it on load was showing the bar the whole time. Found 2026-07-30.10
   while building the patient note panel; it was already true of the pre-visit
   and note panels beside it. */
.previsit-actions[hidden] { display: none; }
.previsit-note {
  font-size: 11.5px;
  color: var(--wf-muted);
  margin: 0;
  max-width: 44ch;
}

/* ---- waiting ----
   An elapsed count rather than a progress bar. Nothing here knows how far along
   the workflow is, and a bar that pretends to would be inventing the number. */

/* Centered in the body, which is a consequence of the definite height above
   rather than a preference on its own. The wait normally runs 15 to 60 seconds,
   so it is the state the panel is in for most of a use, and four lines pinned to
   the top of a panel eight times their height reads as something that failed to
   load. The summary state fills the panel and needs none of this.

   The error state is deliberately left alone. It is short-lived and it is read
   from the top down, where the first line is the actionable one. */
.previsit-wait {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100%;
  padding: 34px 0 30px;
  text-align: center;
}
.previsit-wait-line {
  font: 600 16px var(--wf-serif);
  margin: 0 0 6px;
}
.previsit-elapsed {
  font: 600 26px var(--wf-serif);
  color: var(--wf-terracotta);
  font-variant-numeric: tabular-nums;
  margin: 0 0 10px;
}
.previsit-wait-note {
  font-size: 12.5px;
  color: var(--wf-muted);
  margin: 0 auto 18px;
  max-width: 46ch;
}
.previsit-dots { display: inline-flex; gap: 3px; margin-left: 5px; }
.previsit-dots i {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--wf-terracotta);
  animation: previsit-pulse 1.1s infinite ease-in-out;
}
.previsit-dots i:nth-child(2) { animation-delay: .16s; }
.previsit-dots i:nth-child(3) { animation-delay: .32s; }
@keyframes previsit-pulse {
  0%, 70%, 100% { opacity: .25; }
  35% { opacity: 1; }
}

/* ---- failure ---- */

.previsit-error { padding: 24px 0; }
.previsit-error-line {
  background: var(--wf-abnormal-bg);
  border-left: 3px solid var(--wf-abnormal);
  color: var(--wf-abnormal);
  font-weight: 600;
  font-size: 14px;
  padding: 11px 13px;
  margin: 0 0 14px;
}
/* The one line an operator can act on, so it stays in the open and wraps rather
   than truncating: it carries file paths that have to be readable in full. */
.previsit-setup {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--wf-body);
  background: var(--wf-caution-bg);
  border-left: 3px solid var(--wf-caution);
  padding: 10px 12px;
  margin: 0 0 14px;
  word-break: break-word;
}

.previsit-detail { margin: 0 0 16px; font-size: 12.5px; }
.previsit-detail summary {
  cursor: pointer;
  color: var(--wf-muted);
  font-weight: 600;
}
.previsit-detail pre {
  font: 400 11.5px/1.5 var(--wf-mono);
  background: var(--wf-tint);
  border-radius: 4px;
  padding: 10px 12px;
  margin: 9px 0 0;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--wf-body);
}

.previsit-raw {
  font: 400 12.5px/1.6 var(--wf-mono);
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
  color: var(--wf-body);
}

/* ---- the rendered summary ----
   Reads as a clinical document rather than as a web page: a measure narrow
   enough to scan, serif headings, and tables that match the chart's own. */

.md { max-width: 68ch; }
.md > :first-child { margin-top: 0; }
.md h3 {
  font-size: 18px;
  margin: 24px 0 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--wf-hairline);
}
.md h4 { font-size: 15.5px; margin: 20px 0 6px; }
.md h5, .md h6 {
  font: 700 11.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-muted);
  margin: 18px 0 6px;
}
.md p { margin: 0 0 11px; color: var(--wf-body); }
.md strong { color: var(--wf-ink); }
.md ul, .md ol { margin: 0 0 12px; padding-left: 21px; color: var(--wf-body); }
.md li { margin-bottom: 4px; }
.md li > ul, .md li > ol { margin: 4px 0 0; }
.md hr { border: 0; border-top: 1px solid var(--wf-hairline); margin: 20px 0; }

/* Task list items, which is how a gaps-in-care section arrives. The box is
   decoration around a real state, so it is labeled rather than left as a glyph
   a screen reader has to guess at. */
.md li.md-task { list-style: none; margin-left: -19px; }
.md .md-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 13px;
  height: 13px;
  margin-right: 7px;
  border: 1.5px solid var(--wf-hairline-strong);
  border-radius: 3px;
  font-size: 10px;
  line-height: 1;
  color: transparent;
  vertical-align: -1px;
}
.md .md-box.is-done {
  background: var(--wf-olive);
  border-color: var(--wf-olive);
  color: #FFF;
}
.md blockquote {
  margin: 0 0 12px;
  padding: 2px 0 2px 14px;
  border-left: 3px solid var(--wf-gold);
  color: var(--wf-body);
}
.md blockquote p:last-child { margin-bottom: 0; }
.md code {
  font: 400 12.5px var(--wf-mono);
  background: var(--wf-tint);
  border-radius: 3px;
  padding: 1px 5px;
}
.md pre {
  background: var(--wf-tint);
  border-radius: 5px;
  padding: 12px 14px;
  overflow-x: auto;
  margin: 0 0 12px;
}
.md pre code { background: none; padding: 0; font-size: 12px; line-height: 1.55; }
.md a { font-weight: 600; }

.md-table-scroll { overflow-x: auto; margin: 0 0 14px; }
.md-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.md-table th {
  text-align: left;
  font: 700 10.5px var(--wf-sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--wf-muted);
  padding: 0 12px 7px 0;
  border-bottom: 1px solid var(--wf-hairline-strong);
  white-space: nowrap;
}
.md-table td {
  padding: 8px 12px 8px 0;
  border-bottom: 1px solid var(--wf-hairline);
  vertical-align: top;
  color: var(--wf-body);
}

/* ---------- admin dashboard ---------- */

.bars { list-style: none; margin: 0; padding: 0; font-size: 13px; }
.bars li { padding: 6px 0; }
.bars .bar-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
.bars .track {
  background: var(--wf-tint);
  border-radius: 2px;
  height: 7px;
  overflow: hidden;
}
.bars .fill { background: var(--wf-terracotta); height: 100%; }
.bars .fill.alt { background: var(--wf-olive); }

/* ---------- MyWinterfield ----------

   The patient side reuses the chart's frame wholesale: .chart-sticky,
   .chart-nav, .chart-body, .panel, .stack, table.data. What is here is only what
   the patient pages have that the clinical ones do not, which is money, a lab
   chart, a compose panel, and a row of things to do. Rebuilding the frame in
   patient clothes would mean two copies of the sticky-stacking fix in
   .chart-sticky and the anchor arithmetic that goes with it. */

/* The stat row is a grid inside a grid on these pages, so it needs its own
   column span; the .col-12 in the markup only reaches elements the chart body
   already knows about. */
.stat-row.col-12 { grid-column: span 12; margin-bottom: 0; }

/* The chart marks an abnormal value with color plus an arrow and an H or an L,
   so color is never the only signal. On the patient side the words are already
   in the row, "Above the usual range", and an H beside them is a second copy of
   the same fact written in a language the reader did not ask for. Drop the
   glyph only where the sentence is present; anywhere else the flag keeps it. */
.plain-flags .flag::after, .chart-fact .flag::after { content: none; }

.reach-lede {
  margin: 0 0 14px;
  font-size: 13.5px;
  color: var(--wf-body);
  max-width: 78ch;
}
.reach-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }

/* One of these is a <button> and the rest are <a>. Buttons do not inherit type
   or alignment, so say it once here rather than leaving the note card sitting a
   pixel off from its neighbors in a way nobody can quite name. */
.reach-card {
  font: inherit;
  text-align: left;
  width: 100%;
  cursor: pointer;
}
.reach-card h3 { margin: 0; font-family: var(--wf-serif); }

/* ---------- what a visit cost ---------- */

.charges {
  border: 1px solid var(--wf-hairline);
  border-radius: 6px;
  overflow: hidden;
  max-width: 520px;
}
.charge-row {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding: 10px 14px;
  font-size: 13.5px;
}
.charge-row + .charge-row { border-top: 1px solid var(--wf-hairline); }
.charge-k { color: var(--wf-body); }
.charge-v { font-variant-numeric: tabular-nums; font-weight: 600; }
.charge-row.is-credit .charge-v { color: var(--wf-normal); }
.charge-row.is-total {
  background: var(--wf-tint);
  border-top: 1px solid var(--wf-hairline-strong);
}
.charge-row.is-total .charge-k { font-weight: 700; color: var(--wf-ink); }
.charge-row.is-total .charge-v { font: 600 17px var(--wf-serif); }
.charge-status {
  margin: 11px 0 0;
  font-size: 12.5px;
  color: var(--wf-muted);
  max-width: 62ch;
}
.charge-status .pill { margin-right: 6px; }
.charge-sub { font-size: 14px; margin: 20px 0 8px; }

.pill-paid { background: #E8EDE4; color: var(--wf-normal); }
.pill-due { background: var(--wf-caution-bg); color: var(--wf-caution); }
.pill-overdue { background: var(--wf-abnormal-bg); color: var(--wf-abnormal); }

/* ---------- one result ---------- */

/* The laboratory's own name for a test, printed under the plain-language one in
   a results table. Quiet, because it is the second thing to read, and on its own
   line, because two names on one line reads as one long name. */
.test-formal {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--wf-muted);
}
.lab-formal {
  margin: 16px 0 0;
  max-width: 62ch;
  font-size: 13px;
  color: var(--wf-muted);
}
.lab-formal strong { color: var(--wf-body); }

.lab-headline {
  display: flex;
  gap: 28px;
  align-items: baseline;
  flex-wrap: wrap;
}
.lab-headline-value { display: flex; align-items: baseline; gap: 7px; }
.lab-big { font: 600 44px/1 var(--wf-serif); }
.lab-big.is-out { color: var(--wf-abnormal); }
.lab-unit { font-size: 15px; color: var(--wf-muted); }
.lab-headline-note { flex: 1 1 340px; }
.lab-headline-note p { margin: 0 0 6px; font-size: 13px; }
.lab-state { font-weight: 700; }
.lab-state.is-high, .lab-state.is-low { color: var(--wf-abnormal); }
.lab-state.is-ok { color: var(--wf-normal); }

/* The chart is one inline SVG scaled to the panel. No library: PLAT-09 keeps
   the external dependency list at one entry and a dozen points does not buy a
   second. Points are placed by real date, so a six-year gap looks like one. */
.lab-chart {
  display: block;
  width: 100%;
  height: auto;
  max-height: 260px;
  margin: 4px 0 2px;
  overflow: visible;
}
.lab-band { fill: rgba(74, 93, 67, .13); }
.lab-band-edge { stroke: rgba(74, 93, 67, .5); stroke-width: 1; stroke-dasharray: 3 3; }
.lab-axis-line { stroke: var(--wf-hairline-strong); stroke-width: 1; }
.lab-line {
  fill: none;
  stroke: var(--wf-muted);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.lab-dot { fill: var(--wf-panel); stroke: var(--wf-muted); stroke-width: 1.6; }
.lab-drop { stroke: var(--wf-terracotta); stroke-width: 1; stroke-dasharray: 2 3; }
.lab-dot-current { fill: var(--wf-terracotta); stroke: var(--wf-panel); stroke-width: 2.4; }
.lab-current-label {
  font: 700 12px var(--wf-sans);
  fill: var(--wf-terracotta);
}
.lab-axis { font: 400 11px var(--wf-sans); fill: var(--wf-muted); }
.lab-axis.is-current { font-weight: 700; fill: var(--wf-terracotta); }

.lab-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin: 4px 0 14px;
  font-size: 12px;
  color: var(--wf-muted);
}
.lab-legend .key {
  display: inline-block;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  margin-left: 12px;
}
.lab-legend .key:first-child { margin-left: 0; }
.key-current { background: var(--wf-terracotta); }
.key-dot { background: var(--wf-panel); border: 1.6px solid var(--wf-muted); }
.key-band { background: rgba(74, 93, 67, .3); border-radius: 2px; }

/* ---------- send a note ahead ---------- */

dialog.previsit.ahead { width: min(620px, 94vw); height: auto; max-height: 88vh; }
dialog.previsit.shotdoc { width: min(520px, 94vw); height: auto; max-height: 88vh; }
dialog.previsit.ahead form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}

.ahead-lede { margin: 0 0 16px; font-size: 13.5px; color: var(--wf-body); }
.ahead-label {
  display: block;
  font: 700 11px var(--wf-sans);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--wf-muted);
  margin: 0 0 5px;
}
.ahead-select, .ahead-text {
  width: 100%;
  font: 400 14px/1.5 var(--wf-sans);
  color: var(--wf-ink);
  background: var(--wf-panel);
  border: 1px solid var(--wf-hairline-strong);
  border-radius: 5px;
  padding: 9px 11px;
  margin-bottom: 16px;
}
.ahead-text { resize: vertical; min-height: 120px; }
.ahead-select:focus, .ahead-text:focus {
  outline: 2px solid var(--wf-terracotta);
  outline-offset: 1px;
  border-color: var(--wf-terracotta);
}
.ahead-count { margin: -12px 0 14px; font-size: 11.5px; color: var(--wf-muted); }
.ahead-warn {
  margin: -6px 0 12px;
  font: 700 12.5px var(--wf-sans);
  color: var(--wf-abnormal);
}
.ahead-urgent {
  margin: 0;
  padding: 11px 13px;
  border-left: 3px solid var(--wf-gold);
  background: var(--wf-caution-bg);
  font-size: 12.5px;
  color: var(--wf-body);
}
.ahead-done { text-align: center; padding: 26px 8px 14px; }
.ahead-done svg { color: var(--wf-normal); }
.ahead-done h3 { font-size: 21px; margin: 12px 0 8px; }
.ahead-done p { margin: 0 auto 8px; max-width: 44ch; font-size: 13.5px; color: var(--wf-body); }

/* ---------- footer ---------- */

.portal-footer {
  margin-top: auto;
  background: var(--wf-panel);
  border-top: 1px solid var(--wf-hairline);
  font-size: 12.5px;
  color: var(--wf-muted);
}
.portal-footer .portal-wrap {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  padding-top: 15px;
  padding-bottom: 15px;
}
.portal-footer-links { display: flex; gap: 16px; }
.portal-footer a { text-decoration: none; }
.portal-footer a:hover { text-decoration: underline; }

/* ---------- responsive ----------
   The workspace is a desktop tool and is not pretending otherwise. These
   breakpoints keep it usable on a tablet or a phone rather than optimal: the
   two-column workspace stacks, and the chart's paired columns become one. */

@media (max-width: 1080px) {
  .login-grid { grid-template-columns: 1fr; }
  .work-grid { grid-template-columns: 1fr; }
  .search-panel { position: static; }
  .col-6 { grid-column: span 12; }
  .chart-facts { margin-left: 0; gap: 18px; }
}

@media (max-width: 620px) {
  .portal-wrap { padding: 0 16px; }
  /* Nearly full screen on a phone, and squared off at the bottom because there
     is no backdrop left to see under it. */
  dialog.previsit {
    width: 100vw;
    max-height: 92vh;
    border-radius: 8px 8px 0 0;
    margin: auto 0 0;
  }
  .previsit-body { padding: 16px 16px 20px; }
  .previsit-head, .previsit-foot { padding-left: 16px; padding-right: 16px; }
  .previsit-note { display: none; }
  .work-head, .work-grid, .chart-body, .landing, .login-page { padding-left: 16px; padding-right: 16px; }
  .portal-context { display: none; }
  .chart-sticky { position: static; }
  .chart-body > section { scroll-margin-top: 16px; }
  .account-hint { position: static; display: block; margin-top: 10px; }
  .hint-fill { display: none; }
  .search-form .field-pair { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .op-card:hover { transform: none; }
  /* The global rule above only covers transitions. These two are animations, and
     one of them pulses continuously for the length of the wait. */
  dialog.previsit[open] { animation: none; }
  .previsit-dots i { animation: none; opacity: .6; }
}
