/* Asthma Companion — Broadsheet design system, "Lembar Harian" (canvas 1a).
   Newsprint set for the web: Source Serif 4 near-black on paper white, the
   process accents (cyan #0088b0 + magenta #d6006c, print yellow #edbb00)
   used small and deliberately. Hierarchy from the serif scale and
   whitespace — no cards for layout, hairline rules only.

   The screens changed shape to match the canvas, but every questionnaire,
   the decision engine, the API and the routes are untouched. */
@import url('https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,wght@0,400;0,600;1,400&display=swap');

:root {
  --bg: #f3f2f2;
  --surface: #eae9e9;
  --ink: #201e1d;
  --paper: #f3f2f2;
  --accent: #0088b0;
  --accent-hover: #0088b0;
  --accent-deep: #006786;
  --accent-deeper: #00506a;
  --magenta: #d6006c;
  --emergency: #aa0b56;
  --yellow: #edbb00;
  --yellow-ink: #8a6f00;

  --line: rgba(32, 30, 29, 0.14);
  --line-strong: rgba(32, 30, 29, 0.16);
  --control-border: rgba(32, 30, 29, 0.2);
  /* Alphas chosen so every one clears WCAG AA (4.5:1) on --bg #f3f2f2:
     0.70 -> 5.79, 0.64 -> 4.81. The old 0.6/0.5 measured 4.23 and 3.15. */
  --muted: rgba(32, 30, 29, 0.7);
  --muted-soft: rgba(32, 30, 29, 0.64);
  --disabled: #d7d3d3;
  --disabled-ink: #4f4c4c;

  --serif: "Source Serif 4", Georgia, "Times New Roman", serif;
  --radius: 2px;

  /* legacy aliases kept so the inline-SVG chart helpers keep resolving */
  --green: var(--accent);
  --amber: var(--yellow);
  --red: var(--magenta);
  --border: var(--line);
  --card: var(--surface);
  --muted-color: var(--muted);
  --accent-ink: var(--accent-deep);
  --shadow: none;
  --radius-lg: 4px;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 15px;
  line-height: 1.55;
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

/* Phone-width column. Bottom padding clears the fixed disease bar. */
.wrap {
  max-width: 430px;
  margin: 0 auto;
  padding: 20px 24px;
  padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px));
  min-height: 100vh;
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  letter-spacing: -0.018em;
  line-height: 1.1;
  margin: 0 0 12px;
  text-wrap: pretty;
}
h1 { font-size: 2rem; line-height: 1.06; letter-spacing: -0.022em; }
h2 { font-size: 1.35rem; }
h3 { font-size: 1.28rem; letter-spacing: -0.012em; }
h4 { font-size: 1.05rem; }

p { margin: 0 0 14px; }
p:last-child { margin-bottom: 0; }
a { color: var(--accent-deep); text-underline-offset: 3px; }
a:hover { color: var(--accent); }

:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
::selection { background: rgba(0, 136, 176, 0.28); }

/* ── editorial furniture ─────────────────────────────────────────── */

/* Brand mark: two lung lobes in the process colours with the trachea drawn
   over them in the colour those two inks make when multiplied. It replaced
   the two overlapping dots, which read as a pair but said nothing about what
   the app is for.

   Deliberately ONE background image rather than inline SVG in each topline.
   The mark appears in seven places (five pages plus the toplines rendered by
   quick-check.js and ppok-check.js); the disease bar taught us what happens
   when the same artwork is pasted into several files and only some get
   updated. Change the mark here, or in mark-paru.svg, and every screen
   follows. Regenerate the raster sizes with tools_make_favicon.py.

   18px, not the dots' 16x10: the lung carries internal negative space (the gap
   between the lobes, a 3-of-32 trachea) so it needs a little more room to
   stay legible for the 50+ patients this app is mostly read by. */
.brand-mark {
  display: inline-block;
  width: 18px; height: 18px; flex: 0 0 auto;
  background: url("/static/img/mark-paru.svg?v=20260902f") center / contain no-repeat;
}

/* The mark plus the app name, linking home. Every screen that carries a
   topline gets it, so "Sahabat Napas" is always in view and the way back to
   the landing page is the site logo rather than a fifth tab in the disease
   bar (which is for modules, and where a fifth label would squeeze
   "Tuberkulosis" below a readable size). */
.brandlink {
  display: inline-flex; align-items: center; gap: 9px;
  text-decoration: none; color: var(--ink);
}
.brandname {
  font-family: var(--serif);
  font-size: 12px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink);
}
.brandlink:hover .brandname { color: var(--accent-deep); }

.topline {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 22px;
}

.kick {
  font-family: var(--serif);
  font-size: 11px; font-weight: 400;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted-soft);
  margin: 0 0 8px;
}
.kick-danger { color: var(--emergency); }
/* Kicker sitting above its headline (editorial order). */
.kick-over { margin: 0 0 6px; }
/* Kicker that closes a header block and is followed by content. */
.kick + .q-block, .kick + #items, .kick + #major { margin-top: 18px; }

/* "n dari m terjawab" counter above a disabled submit, so the button is
   never a silent dead end. */
.progress-note {
  font-size: 0.85rem; color: var(--muted);
  margin: 0 0 8px;
}

.crumb {
  font-family: var(--serif);
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted-soft);
}

.lede {
  font-size: 0.95rem; line-height: 1.5;
  color: var(--muted); max-width: none;
  margin: 0 0 26px;
}
.lede-tight { margin-bottom: 14px; }

.section {
  margin-top: 30px; padding-top: 22px;
  border-top: 1px solid var(--line);
}
.section:first-of-type { margin-top: 26px; }

.rule { height: 1px; border: 0; background: var(--line); margin: 22px 0; }

.back {
  display: inline-block;
  background: none; border: 0; padding: 0 0 2px;
  font-family: var(--serif); font-size: 0.85rem;
  color: var(--accent-deep); cursor: pointer;
  margin-bottom: 6px;
}
.back:hover { color: var(--accent); }

/* ── buttons ─────────────────────────────────────────────────────── */

/* full-bleed primary action */
.btn,
.btn-primary,
.bigbtn {
  display: block; width: 100%;
  min-height: 52px; padding: 14px 18px;
  font-family: var(--serif); font-size: 1rem; font-weight: 600;
  line-height: 1.2; text-align: center;
  border: 0; border-radius: var(--radius);
  background: var(--accent-deep); color: var(--paper);
  cursor: pointer; margin-bottom: 10px;
  transition: background 0.15s ease, opacity 0.15s ease, border-color 0.15s ease;
}
.btn:hover,
.btn-primary:not(:disabled):hover,
.bigbtn:hover { background: var(--accent); }
.btn:disabled,
.btn-primary:disabled,
.bigbtn:disabled { background: var(--disabled); color: var(--disabled-ink); cursor: not-allowed; }
.btn-primary:not(:disabled):active,
.bigbtn:active { background: var(--accent-deeper); }

/* emergency-tinted primary (danger hard stop) */
.bigbtn-danger, .btn-danger { background: var(--emergency); }
.bigbtn-danger:hover, .btn-danger:hover { background: #93094a; }

/* outline / secondary */
.btn-secondary,
.btn-outline {
  display: block; width: 100%;
  min-height: 52px; padding: 14px 18px;
  font-family: var(--serif); font-size: 1rem; font-weight: 600;
  line-height: 1.2; text-align: center;
  background: transparent; color: var(--ink);
  border: 1px solid var(--control-border); border-radius: var(--radius);
  cursor: pointer; margin-bottom: 10px;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.btn-secondary:not(:disabled):hover,
.btn-outline:hover { border-color: var(--accent); }

/* quiet placeholder button (Edukasi / notify) */
.btn-quiet {
  display: block; width: 100%;
  min-height: 48px; padding: 12px 16px;
  font-family: var(--serif); font-size: 0.95rem; font-weight: 400;
  text-align: center;
  background: transparent; color: rgba(32, 30, 29, 0.7);
  border: 1px solid var(--control-border); border-radius: var(--radius);
  cursor: pointer; margin-bottom: 10px;
}
.btn-quiet:hover { border-color: var(--accent); }

/* inline text link-button */
.linkbtn {
  display: inline-block;
  background: none; border: 0; padding: 8px 0;
  font-family: var(--serif); font-size: 0.86rem; font-weight: 400;
  color: var(--accent-deep); cursor: pointer; text-align: left;
}
.linkbtn:hover { color: var(--accent); }

/* ── Ya / Tidak pair ─────────────────────────────────────────────── */
.btn-row, .yn-row { display: flex; gap: 10px; margin-top: 12px; }
.btn-row .btn, .btn-row .qbtn { margin-bottom: 0; }

.qbtn, .btn-yes, .btn-no {
  flex: 1; min-height: 50px; margin: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font-family: var(--serif); font-size: 0.98rem; font-weight: 600;
  border: 1.5px solid var(--control-border); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.qbtn:hover, .btn-yes:hover, .btn-no:hover { border-color: var(--accent); }

/* Selected: solid fill + a ✓ marker. "Ya" is the finding (cyan),
   "Tidak" is neutral ink. */
.btn-yes.selected, .qbtn.sel-yes {
  background: var(--accent-deep); color: #fff; border-color: var(--accent-deep); font-weight: 600;
}
.btn-no.selected, .qbtn.sel-no {
  background: var(--ink); color: #fff; border-color: var(--ink); font-weight: 600;
}
.qbtn.sel-yes::before, .qbtn.sel-no::before,
.btn-yes.selected::before, .btn-no.selected::before {
  content: "✓"; font-size: 0.9em;
}
/* The sibling that was NOT chosen: recede to a plain quiet outline —
   clearly "off", not disabled. */
.qbtn.is-off, .btn-yes.is-off, .btn-no.is-off {
  background: transparent; color: var(--muted); border-color: var(--line);
  font-weight: 400;
}

.q-block { margin-bottom: 24px; }
.q-block > p, .q-text {
  margin: 0; font-size: 1.03rem; line-height: 1.38; text-wrap: pretty;
}
.q-note { margin: 6px 0 0; font-size: 0.85rem; color: var(--muted); }

/* PPOK Bagian 2 — the "then vs now" contrast markers. The all-caps already
   carries the contrast, so only HARI INI (the thing being asked about) is
   tinted. BIASANYA used to be magenta, which is this system's danger colour
   and made the least urgent screen the most alarming one. */
.w-biasa { font-weight: 600; color: var(--ink); }
.w-kini  { font-weight: 600; color: var(--accent-deep); }

/* progress counter on a submit button */
.progress { font-size: 0.8rem; color: var(--muted); margin-bottom: 8px; }
.step-heading {
  font-family: var(--serif); font-size: 1.75rem; font-weight: 600;
  line-height: 1.08; letter-spacing: -0.02em;
  margin: 2px 0 8px; border: 0; padding: 0;
}

/* ── forms ───────────────────────────────────────────────────────── */
input[type=text], input[type=password], input[type=number], select {
  width: 100%; padding: 11px 12px;
  font: inherit; font-size: 0.95rem; color: var(--ink);
  caret-color: var(--accent);
  background: var(--bg);
  border: 1px solid var(--control-border); border-radius: var(--radius);
  margin-bottom: 12px;
}
input:focus, select:focus { outline: none; border-color: var(--accent); }
input:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }

label {
  display: block; font-size: 0.85rem; margin-bottom: 6px;
  color: rgba(32, 30, 29, 0.7); font-weight: 400;
}
label input[type=checkbox] { width: auto; margin-right: 8px; }

/* ── Cek Cepat result plate ──────────────────────────────────────── */
.plate-bar { height: 6px; width: 92px; margin: 4px 0 18px; background: var(--muted); }
.plate-title { font-size: 2.1rem; line-height: 1.04; letter-spacing: -0.022em; margin: 0 0 12px; max-width: 15ch; }
.plate-note { font-size: 0.98rem; line-height: 1.55; color: rgba(32, 30, 29, 0.78); max-width: none; margin: 0 0 26px; }

.outcome-green .plate-bar { background: var(--accent); }
.outcome-green .plate-title { color: var(--accent-deep); }
.outcome-amber .plate-bar { background: var(--yellow); }
.outcome-amber .plate-title { color: var(--yellow-ink); }
.outcome-red .plate-bar { background: var(--magenta); }
.outcome-red .plate-title { color: var(--emergency); }

/* PPOK Cek Cepat — the five bands must read as an escalation, so severity
   drives BOTH the bar colour and the bar length. All boxless: the tinted
   panel the SANGAT_BERAT band used to carry was the only filled box in the
   app and broke the "hairline rules only" rule of the design system.
     LANJUTKAN_BIASA -> .outcome-green   (cyan,  92px)
     SEDANG_RINGAN   -> .outcome-amber   (yellow, 92px)
     BERAT           -> .pp-berat        (deep amber, 124px)
     SANGAT_BERAT    -> .pp-sangat       (magenta,    160px)
     IGD_WAJIB       -> .emergency       (full-bleed plate) */
.pp-berat .plate-bar { background: var(--yellow-ink); width: 124px; }
.pp-berat .plate-title { color: var(--yellow-ink); }

.pp-sangat .plate-bar { background: var(--magenta); width: 160px; height: 8px; }
.pp-sangat .plate-title { color: var(--emergency); }

/* numbered "01 / 02 / 03" step list */
.steps { display: flex; flex-direction: column; gap: 14px; margin: 0 0 30px; }
.steps .step { display: flex; gap: 12px; align-items: baseline; }
.steps .step .n { font-weight: 600; font-size: 0.8rem; color: var(--accent); min-width: 14px; }
.steps .step .t { font-size: 0.95rem; line-height: 1.45; text-wrap: pretty; }

/* a plain guidance paragraph block (real API returns prose, not steps) */
.callout {
  border-left: 2px solid var(--line-strong);
  padding: 2px 0 2px 14px;
  margin: 0 0 24px;
  font-size: 0.95rem; line-height: 1.5;
  color: rgba(32, 30, 29, 0.78);
}
.callout-accent { border-left-color: var(--accent); }
.callout-danger { border-left-color: var(--emergency); color: var(--emergency); }

.info-note {
  border-left: 2px solid var(--accent);
  padding: 2px 0 2px 14px; margin: 0 0 20px;
  font-size: 0.9rem; line-height: 1.5; color: var(--accent-deep);
}

/* Submit failure. Deliberately NOT the emergency plate: a network error is
   not a clinical finding, and the plate's "TANDA BAHAYA" kicker said it was. */
.notice {
  border-left: 2px solid var(--line-strong);
  padding: 2px 0 2px 14px; margin: 0 0 24px;
  font-size: 0.95rem; line-height: 1.5; color: var(--muted);
}

.error   { color: var(--emergency); font-size: 0.88rem; font-weight: 600; }
.success { color: var(--accent-deep); font-size: 0.88rem; font-weight: 600; }
.muted { color: var(--muted); font-size: 0.85rem; }
.hidden { display: none !important; }

/* ── inline danger stop (Bagian 1) ─────────────────────────────── */
.danger-block {
  margin-top: 22px; padding-top: 20px;
  border-top: 1px solid var(--line);
}

/* ── emergency result — full-bleed plate, one-tap call ─────────── */
.emergency { margin: -20px -24px 0; }
.emergency-plate {
  background: var(--emergency); color: #fff;
  padding: 36px 24px 30px;
}
.emergency-kicker {
  margin: 0 0 12px;
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
}
.emergency-title {
  margin: 0 0 14px;
  font-family: var(--serif); font-weight: 600;
  font-size: 2.25rem; line-height: 1.05; letter-spacing: -0.02em;
  color: #fff;
}
.emergency-body {
  margin: 0; max-width: none;
  font-size: 1.05rem; line-height: 1.55; color: #fff;
}
.emergency-foot { padding: 18px 24px 0; }

/* ── Monitor Harian containers ──────────────────────────────────────
   The Cek Cepat flow is boxless (canvas 1a); the logged-in Monitor
   screens keep a flat container to hold their stats and charts —
   serif, 2px radius, hairline, no shadow. Not the old rounded card. */
.card {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 4px;
  box-shadow: none;
  padding: 18px;
  margin-bottom: 14px;
}
.card h2 { font-size: 1.15rem; }
.card.outcome-green { border-left: 3px solid var(--accent); }
.card.outcome-amber { border-left: 3px solid var(--yellow); }
.card.outcome-red   { border-left: 3px solid var(--magenta); }
.card.info-note { border: 1px solid var(--line); border-left: 2px solid var(--accent); padding: 14px 16px; }
.card table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.card th { text-align: left; font-weight: 600; font-size: 0.72rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted); padding: 6px 4px; border-bottom: 1px solid var(--line); }
.card td { padding: 6px 4px; border-bottom: 1px solid var(--line); }
.card ul { margin: 8px 0 0; padding-left: 20px; }
.card li { margin-bottom: 4px; }

/* ── recent-log rows / doctor-summary rows ───────────────────────── */
.rows { display: flex; flex-direction: column; }
.row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; padding: 13px 0; border-bottom: 1px solid var(--line);
}
.row .row-main { font-size: 0.95rem; }
.row .row-sub { font-size: 0.8rem; color: var(--muted-soft); margin-top: 2px; }
.row .row-val { font-weight: 600; font-size: 0.95rem; }

/* ── dark "for the doctor" panel ─────────────────────────────────── */
.ink-panel {
  background: var(--ink); color: var(--paper);
  border-radius: 4px; padding: 18px; margin: 14px 0;
}
.ink-panel .kick { color: rgba(243, 242, 242, 0.55); }
.ink-panel .row { border-bottom-color: rgba(243, 242, 242, 0.16); }
.ink-panel .row-main { color: rgba(243, 242, 242, 0.7); }
.ink-panel a, .ink-panel .linkbtn { color: #99e0ff; }

/* ── the "Segera" chip ──────────────────────────────────────────── */
.chip-soon {
  display: inline-block;
  font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted-soft);
  border: 1px solid rgba(32, 30, 29, 0.22); border-radius: var(--radius);
  padding: 2px 5px; margin-left: 8px; vertical-align: middle;
}
.soon { /* legacy alias */
  font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted-soft);
  border: 1px solid rgba(32, 30, 29, 0.22); border-radius: var(--radius);
  padding: 2px 5px;
}

/* ── reliever-count scroll picker ────────────────────────────────── */
.scroll-picker {
  display: flex; overflow-x: auto; gap: 8px;
  padding: 6px 2px 10px; -webkit-overflow-scrolling: touch;
}
.scroll-item {
  flex: 0 0 auto; min-width: 44px; min-height: 44px;
  padding: 10px 14px;
  border: 1px solid var(--control-border); border-radius: var(--radius);
  background: transparent;
  font-family: var(--serif); font-size: 0.98rem; font-weight: 600;
  color: var(--ink); cursor: pointer;
}
.scroll-item:hover { border-color: var(--accent); }
.scroll-item.selected {
  background: var(--accent-deep); color: var(--paper); border-color: var(--accent-deep);
}

/* ── disease bottom bar (global, canvas 1a) ─────────────────────── */
nav.tabbar, .dbar {
  position: fixed; left: 0; right: 0; bottom: 0;
  z-index: 200;
  display: flex; width: 100%; max-width: none;
  background: var(--bg);
  border: 0; border-top: 1px solid var(--line-strong);
  border-radius: 0; box-shadow: 0 -1px 8px rgba(45, 43, 43, 0.06);
  padding: 0 0 env(safe-area-inset-bottom, 0px);
  transform: none; backdrop-filter: none;
}
nav.tabbar a, nav.tabbar button, .dtab {
  flex: 1; min-height: 60px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer;
  font-family: var(--serif); font-size: 0.95rem; font-weight: 400;
  color: var(--muted); text-decoration: none;
  border-radius: 0;
  transition: color 0.15s ease, box-shadow 0.15s ease;
}
/* "Profil Dokter" is stacked onto two lines (see diseasebar.js); the span
   is what wraps, the button stays a centred flex box of the same height. */
nav.tabbar .tab-label { text-align: center; line-height: 1.2; }
nav.tabbar a.active, nav.tabbar button.active, .dtab[data-on="1"], .dtab.active {
  color: var(--accent-deep); font-weight: 600;
  background: transparent;
  box-shadow: inset 0 2px 0 var(--accent-deep);
}

/* section switcher at the top of each Monitor screen — plain serif links
   (Broadsheet is boxless); the current view carries an accent underline. */
.subnav {
  display: flex; gap: 22px;
  margin: 2px 0 24px;
}
.subnav a {
  font-family: var(--serif); font-size: 0.92rem; font-weight: 600;
  color: var(--muted); text-decoration: none;
  padding-bottom: 4px;
}
.subnav a:hover { color: var(--accent); }
.subnav a.active {
  color: var(--ink);
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* ── mMRC option list (Monitoring Harian PPOK) ───────────────────────
   Five long statements, so the yes/no pair is the wrong control: one
   full-width row each, graded number on the left, hairline rules only. */
.mmrc-list { display: flex; flex-direction: column; margin: 0 0 24px; }
.mmrc-opt {
  display: flex; gap: 12px; align-items: baseline; text-align: left;
  width: 100%; padding: 14px 12px 14px 0;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  border-radius: 0; cursor: pointer;
  font-family: var(--serif); font-size: 0.95rem; line-height: 1.45;
  color: var(--ink);
}
.mmrc-opt:first-child { border-top: 1px solid var(--line); }
.mmrc-opt:hover { color: var(--accent-deep); }
.mmrc-opt.selected { color: var(--accent-deep); font-weight: 600; }
.mmrc-opt.selected .mmrc-text { box-shadow: inset 0 -2px 0 var(--accent); }

/* status dots on the Ringkasan criteria list */
.dot-list { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
.dot-list span.item { display: flex; align-items: center; gap: 8px; font-size: 0.85rem; }
.dot-list i {
  width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
}

/* A checkbox row sitting straight against the submit button read as part
   of the button; the signup form is the only place this pairing occurs. */
label + .btn-primary { margin-top: 14px; }

/* A follow-up question that only appears once its parent is answered
   "Ya". Indented under the question that opened it so it reads as part
   of that answer rather than as a new, unrelated item. */
.q-followup {
  margin-left: 14px; padding-left: 14px;
  border-left: 2px solid var(--line-strong);
}

/* Four tabs, one of them "Tuberkulosis". Equal columns would have to shrink
   the type to fit the longest label into a quarter of a 360px screen, and
   this bar is read by patients who are mostly over 50. So the tabs size to
   their content instead and the type stays at 0.9rem: "Asma" and "PPOK"
   take the width they need and hand the rest to the long labels. */
nav.tabbar a, nav.tabbar button {
  font-size: 0.9rem;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0 4px;
}
nav.tabbar .tab-label { hyphens: none; overflow-wrap: normal; }

/* An entry too old to describe today keeps its band colour on the dots and
   the ring, but loses the coloured card edge: a full red rail read as a
   live alarm when the record behind it was three weeks old. */
.card-stale { border-left: 3px solid var(--line-strong); }
.dot-state { display: block; font-size: 0.78rem; color: var(--muted); }
.dot-list span.item { align-items: flex-start; }
.dot-list i { margin-top: 4px; }

/* ── TB module ───────────────────────────────────────────────────────
   No new visual language. The TB tiers map onto bands the other two
   modules already use, and the only genuinely new controls are the ones
   the profile form needs (a date field, a free-text box for the
   clinician's standing instruction, a multi-select list). */

/* Date and textarea were never styled because no screen had one until the
   TB profile form; without this they render as the browser default and are
   the only sans-serif controls in the app. */
input[type=date], textarea {
  width: 100%; padding: 11px 12px;
  font: inherit; font-size: 0.95rem; color: var(--ink);
  caret-color: var(--accent);
  background: var(--bg);
  border: 1px solid var(--control-border); border-radius: var(--radius);
  margin-bottom: 12px;
}

/* iOS Safari lays a date input out from the native control rather than from
   the box we asked for: it keeps an intrinsic minimum width derived from the
   rendered value, so `width: 100%` does not hold it inside the column, and it
   centres the value while every other field in this app is left aligned.
   Desktop Safari does neither, which is why this only shows up on a phone.

   Dropping the native appearance and clamping the width fixes both. The date
   picker still opens on tap; only the chrome around it goes. */
input[type=date] {
  -webkit-appearance: none;
  appearance: none;
  min-width: 0;
  max-width: 100%;
}
input[type=date]::-webkit-date-and-time-value {
  text-align: left;
  margin: 0;
}
/* The picker button, kept visible and pushed to the trailing edge now that
   the native layout is gone. */
input[type=date]::-webkit-calendar-picker-indicator { margin-left: auto; }

/* Belt and braces: nothing inside the reading column may exceed it. A
   control that overhangs is always a bug, and this stops the next one
   reaching a patient's phone. */
.wrap input, .wrap select, .wrap textarea, .wrap button, .wrap .btn { max-width: 100%; }
textarea { min-height: 92px; line-height: 1.5; resize: vertical; }
input[type=date]:focus, textarea:focus { outline: none; border-color: var(--accent); }
input[type=date]:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 0;
}

/* ORANGE, "periksakan diri HARI INI", takes the magenta band PPOK gives
   SANGAT BERAT: same "today, not later" urgency, so it gets the same
   treatment rather than a fifth one nobody has learned to read. TB's RED
   uses the full-bleed .emergency plate, as every module's hard stop does. */
.tb-orange .plate-bar { background: var(--magenta); width: 160px; height: 8px; }
.tb-orange .plate-title { color: var(--emergency); }

/* The multi-select rows of the TB profile ("which medicines", "which other
   drugs"): the mMRC row list, but several answers can be on at once, so the
   chosen ones carry a filled marker instead of an underline. */
.pick-list { display: flex; flex-direction: column; margin: 0 0 20px; }
.pick-opt {
  display: flex; gap: 12px; align-items: center; text-align: left;
  width: 100%; padding: 13px 12px 13px 0;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  border-radius: 0; cursor: pointer;
  font-family: var(--serif); font-size: 0.95rem; line-height: 1.45;
  color: var(--ink);
}
.pick-opt:first-child { border-top: 1px solid var(--line); }
.pick-opt:hover { color: var(--accent-deep); }
.pick-opt .box {
  flex: 0 0 auto; width: 16px; height: 16px;
  border: 1px solid var(--control-border); border-radius: var(--radius);
}
.pick-opt.selected { color: var(--accent-deep); font-weight: 600; }
.pick-opt.selected .box {
  background: var(--accent-deep); border-color: var(--accent-deep);
  box-shadow: inset 0 0 0 2px var(--bg);
}

/* Form sections on the TB profile. A hairline and a kicker, not a card:
   the page has two owners (patient and clinician) and the split has to be
   legible without introducing a boxed panel. */
.form-section { border-top: 1px solid var(--line-strong); margin: 30px 0 0; padding-top: 18px; }
.form-section > h3 { margin: 0 0 4px; }
/* A form-section holding only its heading still has to leave room for the
   control that follows it. */
.form-section > h3:only-child { margin-bottom: 14px; }
.form-section .lede { margin-bottom: 18px; }

/* Riwayat rows: date on the left, tier on the right, dot carrying the band
   colour. Same .row rhythm the Monitor screens use. */
.tier-dot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin-right: 8px; flex: 0 0 auto;
}

/* Clinician block on /tb/ringkasan. Deliberately the ink panel: it is the
   one part of this app addressed to a clinician rather than a patient, and
   it carries rule ids and diagnosis names that must never read as the
   patient's own result. */
.clinician-block { margin-top: 30px; }
.clinician-block .payload {
  font-size: 0.82rem; line-height: 1.5;
  border-left: 2px solid var(--line-strong); padding-left: 12px; margin: 10px 0 0;
}
.clinician-block .payload dt {
  font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted-soft); margin-top: 10px;
}
.clinician-block .payload dd { margin: 2px 0 0; }

/* ORANGE and RED sit one step apart on a magenta-to-crimson ramp, which is
   plain enough on a 160px plate bar and nearly identical on a 10px dot. The
   emergency tier gets a ring as well as its hue, so the two are told apart
   by shape and not by colour alone. Every list that uses these dots also
   names the tier in words; this is the third cue, not the only one. */
.tier-dot[data-tier="RED"], .dot-list i[data-tier="RED"] {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--emergency);
}

/* "Tahan 14 hari" wrapped onto two lines inside the flex row and read as
   two controls. The row's label is what should wrap, not its action. */
.rows .row > .linkbtn { white-space: nowrap; flex: 0 0 auto; margin-left: 12px; }

/* ── Habit Tracker OAT ───────────────────────────────────────────────
   Still Broadsheet: hairlines, no cards, the accent used small. The one
   loud element is the dose button, and deliberately so, because it is the
   only thing most visits to this screen are for. */

/* The single primary action. Taller than .bigbtn: it is a thumb target on
   a screen a patient opens once a day, half of them over 50. */
.dose-btn {
  width: 100%; min-height: 68px;
  padding: 20px 18px; margin: 0 0 10px;
  border: 1px solid var(--accent-deep); border-radius: var(--radius);
  background: var(--accent-deep); color: var(--paper);
  font-family: var(--serif); font-size: 1.12rem; font-weight: 600;
  cursor: pointer;
}
.dose-btn:hover { background: var(--accent); border-color: var(--accent); }
.dose-btn:active { background: var(--accent-deeper); }
.dose-btn:disabled { opacity: 0.6; cursor: default; }

/* Recorded. Reads as a settled fact rather than a button waiting to be
   pressed, but stays a real button so it can be undone. */
.dose-btn.is-done {
  background: transparent; color: var(--accent-deep);
  border: 2px solid var(--accent-deep);
}
.dose-btn.is-done:hover { background: transparent; }

/* ── block calendar ──────────────────────────────────────────────────
   One square per day of the current block. A blank square means the day was
   not recorded here, which is NOT the same as a missed dose and is never
   drawn as an error: no red, no strike, no warning colour anywhere in this
   grid. */
.cal-grid {
  display: grid; grid-template-columns: repeat(7, 1fr);
  gap: 6px; margin: 8px 0 10px;
}
/* Weekday header, Monday first as Indonesian calendars are printed. */
.cal-head {
  display: grid; grid-template-columns: repeat(7, 1fr);
  gap: 6px; margin-top: 12px;
  font-size: 0.72rem; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--muted-soft); text-align: center;
}
/* The blanks before the 1st and after the last. Not days, so not squares. */
.cal-pad { aspect-ratio: 1; }
/* Month title and its two arrows. */
.cal-nav {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-top: 18px;
}
.cal-nav .month { font-size: 1.05rem; font-weight: 600; }
.cal-nav button {
  background: none; border: 0; cursor: pointer; padding: 6px 10px;
  font-family: var(--serif); font-size: 1rem; color: var(--accent-deep);
  min-width: 44px; min-height: 40px;
}
.cal-nav button:disabled { color: var(--muted-soft); cursor: default; }
/* A <div>, not a <button>: the record is closed once the day is over, so
   nothing in this grid is tappable and nothing should look as if it is. */
.cal-day {
  /* No min-height. With aspect-ratio: 1 it also sets a minimum *width*, and
     seven 40px cells plus their gaps do not fit a 320px screen: the grid
     overhung the column by 44px and scrolled the whole page sideways. The
     40px was there for tap targets, and nothing in this grid is tappable any
     more, so the column width can decide the size. */
  aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: transparent;
  font-family: var(--serif); font-size: 0.9rem; color: var(--muted);
  padding: 0;
}
/* Days before treatment started, and days in a month the patient was not
   on OAT: shown so the month reads as a month, but plainly not part of the
   record. */
.cal-day.is-outside { border-color: transparent; color: var(--muted-soft); opacity: 0.45; }
.cal-day.is-recorded {
  background: var(--accent-deep); border-color: var(--accent-deep);
  color: var(--paper); font-weight: 600;
}
.cal-day.is-today { box-shadow: inset 0 0 0 2px var(--magenta); }
/* A day that has not arrived yet is not a gap. Faint, and not tappable. */
.cal-day.is-future {
  border-style: dashed; border-color: var(--line);
  color: var(--muted-soft); opacity: 0.5; cursor: default;
}
.cal-legend {
  display: flex; flex-wrap: wrap; gap: 14px;
  font-size: 0.78rem; color: var(--muted); margin-bottom: 4px;
}
.cal-legend span { display: flex; align-items: center; gap: 6px; }
.cal-legend i {
  width: 12px; height: 12px; border-radius: var(--radius);
  border: 1px solid var(--line-strong); flex: 0 0 auto;
}
.cal-legend i.on { background: var(--accent-deep); border-color: var(--accent-deep); }
.cal-legend i.now { box-shadow: inset 0 0 0 2px var(--magenta); }

/* ── phase ───────────────────────────────────────────────────────────
   Progress is carried by bar length, the same axis the result plates use. */
.phase-line { margin: 0 0 4px; }
.phase-name {
  font-size: 1.35rem; line-height: 1.15; letter-spacing: -0.012em;
  margin: 2px 0 6px;
}
.phase-track {
  height: 6px; width: 100%; background: var(--line);
  border-radius: var(--radius); overflow: hidden; margin: 10px 0 8px;
}
.phase-fill { height: 100%; background: var(--accent); }
.phase-fill.lanjutan { background: var(--accent-deep); }

/* The whole course, one row per block. Hairline rules; the current block is
   the only one that carries weight. */
.phase-list { display: flex; flex-direction: column; margin: 12px 0 0; }
.phase-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 11px 0; border-bottom: 1px solid var(--line);
  font-size: 0.92rem;
}
.phase-row:first-child { border-top: 1px solid var(--line); }
.phase-row .when { font-size: 0.78rem; color: var(--muted-soft); display: block; }
.phase-row .count { color: var(--muted); font-size: 0.85rem; white-space: nowrap; }
.phase-row.is-current { color: var(--accent-deep); font-weight: 600; }
.phase-row.is-current .count { color: var(--accent-deep); }
/* A block still in the future is dimmed, never labelled as missed. */
.phase-row.is-later { color: var(--muted-soft); }
.phase-head {
  font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted-soft); margin: 22px 0 2px;
}

/* Two or three plain numbers side by side. No ring charts, no badges: this
   is a record, not a game. */
.stat-row { display: flex; gap: 26px; margin: 18px 0 6px; }
.stat-row .stat .n {
  font-size: 1.7rem; line-height: 1; letter-spacing: -0.02em; display: block;
}
.stat-row .stat .l { font-size: 0.78rem; color: var(--muted); }

/* ── Profil Dokter ───────────────────────────────────────────────────
   One editorial page, no new furniture: the head is a portrait beside the
   name, and both lists below reuse .rows/.row from the Monitor screens
   (main + sub on the left, the value right-aligned) so the schedule reads
   like the summary rows patients already know.

   The photograph is a studio shot on white. Newsprint has no colour
   portraits, so it is desaturated and multiplied onto the paper, which also
   makes its white ground disappear into --bg instead of sitting on it as a
   visible rectangle. */
.doc-head { display: flex; gap: 16px; align-items: flex-start; margin: 0 0 18px; }
.doc-portrait {
  flex: 0 0 116px; width: 116px; aspect-ratio: 4 / 5;
  overflow: hidden; border-radius: var(--radius);
}
.doc-portrait img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 6%;
  filter: grayscale(1) contrast(1.06);
  mix-blend-mode: multiply;
}
.doc-name { font-size: 1.6rem; line-height: 1.12; margin: 0 0 9px; color: var(--accent-deep); }
/* The two title lines are the doctor's credentials, not body copy. Grey read
   as "more paragraph" and near-black read as body too; the gold that
   separated them properly was unpleasant to read at this length. Cool
   blue-grey separates by temperature instead: the prose under it is a warm
   ink grey, so the block reads apart without another saturated colour next
   to the cyan name. 8.1:1 on --bg. */
.doc-role { font-size: 0.94rem; line-height: 1.4; color: #40525c; margin: 0; }
.doc-role span { display: block; }
.doc-role span + span { margin-top: 4px; }

/* Emphasis inside the profile prose. .lede is set in --muted, so a bold run
   inside it also has to come back up to --ink or it reads as heavier grey
   rather than as emphasis. .hl is for the one phrase that carries the
   page (personalized care) and stays rare: this design system spends its
   accent sparingly. */
.lede strong { font-weight: 600; color: var(--ink); }
.lede .hl { font-weight: 600; color: var(--accent-deep); }

/* Section labels on Profil Dokter. The app-wide .kick is a quiet 11px grey
   caption sitting above questionnaire content; here it is the only thing
   dividing three long lists, so it is bigger, bold and in full --ink. */
.kick-head {
  font-size: 13px; font-weight: 600;
  letter-spacing: 0.11em; color: var(--ink);
  margin-bottom: 12px;
}

/* Jadwal praktek. A day can hold more than one session, so the day is the
   row and the sessions sit under it, each keeping the hospital left and the
   hours right. An earlier version gave every session its own .row and left
   the day name blank on the second one, which read as a row with a missing
   day rather than as a second session of the same day. */
.sched-day { padding: 13px 0; border-bottom: 1px solid var(--line); }
.sched-day .day { font-size: 0.95rem; margin: 0 0 5px; }
.sched-sesi {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
}
.sched-sesi + .sched-sesi { margin-top: 7px; }
.sched-sesi .place { font-size: 0.85rem; color: var(--muted); }
.sched-sesi .jam { font-weight: 600; font-size: 0.95rem; white-space: nowrap; }

/* ── Landing (Sahabat Napas) ─────────────────────────────────────────
   The front door a domain visitor lands on before entering a module. It is
   the one screen with no disease bar, because the bar is what the app puts
   under a patient once they are inside a module; here the four tiles are
   that choice, made full size. */
.wrap-solo { padding-bottom: 32px; }

.landing-title { font-size: 2.5rem; margin-bottom: 10px; }

/* The three conditions are the app's real choice, so they are full-width
   rows a thumb can hit and a 50+ patient can read without squinting. Profil
   Dokter used to sit as a fourth tile under "Pilih kondisi Anda", which
   named it a condition; it is now a quieter row of its own below the rule.
   The tiles are controls, so they carry the same hairline border as
   .btn-outline rather than becoming cards. */
.menu-list { display: flex; flex-direction: column; gap: 10px; margin: 0; }
.menu-tile {
  display: flex; flex-direction: column; gap: 4px;
  padding: 15px 16px;
  border: 1px solid var(--control-border); border-radius: var(--radius);
  background: transparent; color: var(--ink); text-decoration: none;
}
.menu-tile:hover { border-color: var(--accent); color: var(--ink); }
.menu-tile .t { font-size: 1.1rem; font-weight: 600; line-height: 1.15; }
.menu-tile .s { font-size: 0.85rem; line-height: 1.35; color: var(--muted); }

/* Secondary destination: no border, so it reads as a link out of the list
   rather than a fourth condition. */
/* A labelled block of its own, not a bordered tile: a box here carried the
   same weight as the three condition tiles and read as a fourth condition
   dropped into the middle of the prose. The section rule and the kicker
   above it do the separating, and the cyan label with its arrow does the
   affording. */
.menu-aside {
  display: flex; flex-direction: column; gap: 3px;
  padding: 0; color: var(--ink); text-decoration: none;
}
.menu-aside .t { font-size: 1.06rem; font-weight: 600; color: var(--accent-deep); }
.menu-aside:hover .t { text-decoration: underline; text-underline-offset: 3px; }
.menu-aside .s { font-size: 0.85rem; color: var(--muted); line-height: 1.35; }

.landing-foot {
  margin-top: 34px; padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: 0.8rem; color: var(--muted-soft);
}
.landing-foot p { margin: 0; }
