/* Hand-authored primitives that mirror the app's shared components. Every color,
   font size, and gap here reads a variable from generated/tokens.css, so the
   pixel geometry (radii, paddings, touch targets) is the only thing kept by hand.
   Those numbers come straight from the matching component and change rarely:
   Card.tsx, FieldValueRow.tsx, AppSegmentedControl.tsx, Badge.tsx, CheckSelectList.tsx. */

* {
  box-sizing: border-box;
}

.help-kit {
  margin: 0;
  background: #15171c;
  color: #e7e7ea;
  font-family:
    "Satoshi",
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* ---- device frame -------------------------------------------------------- */
/* Fixed 393x852 (iPhone 15 logical size). Every screen shares these dimensions,
   so exported PNGs are identical in size and sit uniformly in an article. */

/* Declared on the frame itself, not only on body, so a PNG export (which clones
   the frame without a body above it) still resolves Satoshi instead of falling
   back to the browser's default serif. */
.phone,
.stage {
  font-family:
    "Satoshi",
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    sans-serif;
}

.phone {
  --screen-w: 393px;
  --screen-h: 852px;
  width: calc(var(--screen-w) + 24px);
  height: calc(var(--screen-h) + 24px);
  padding: 12px;
  background: #05060a;
  border-radius: 52px;
  /* A metal band, then a faint light hairline outside it so the frame keeps a
     visible edge on a dark surface (the in-app help ground). No drop shadow. */
  box-shadow:
    0 0 0 2px #23252c,
    0 0 0 3.5px rgba(255, 255, 255, 0.14);
}

.screen {
  position: relative;
  width: var(--screen-w);
  height: var(--screen-h);
  border-radius: 40px;
  overflow: hidden;
  background: var(--gradient);
  color: var(--text-base);
  display: flex;
  flex-direction: column;
}

/* ---- stage --------------------------------------------------------------- */
/* A fixed-width transparent window. The width and the phone size stay constant
   across every step; only the height varies, so each step shows as much of the
   screen as it needs and crops the rest. The phone is anchored to the top, so a
   shorter height crops from the bottom. Set the height per shot with --stage-h. */
.stage {
  --stage-w: 460px;
  --stage-h: 560px;
  position: relative;
  width: var(--stage-w);
  height: var(--stage-h);
  overflow: hidden;
  background: var(--stage-bg, transparent);
}

.stage .phone {
  position: absolute;
  left: 50%;
  top: var(--phone-top, 24px);
  transform: translateX(-50%);
}
/* The display viewport for one shot. The runtime scales the stage to fill it. */
.thumb {
  display: block;
  width: 100%;
  overflow: hidden;
}

/* ---- status bar ---------------------------------------------------------- */

/* No time, notch, or signal glyphs. A plain top inset keeps the header off the
   rounded corner and reads as a generic phone rather than iOS or Android. */
.statusbar {
  height: 32px;
  flex-shrink: 0;
}

/* ---- screen header (pushed screens) ------------------------------------- */

.screen-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 20px 12px;
}

.screen-header .back {
  display: flex;
  align-items: center;
  color: var(--text-base);
}

/* The back control is a left arrow, not a chevron. Drawn as a mask so it takes
   the header's text color; the markup's chevron span is hidden. */
.screen-header .back .chevron {
  display: none;
}

.screen-header .back::before {
  content: "";
  display: block;
  width: 22px;
  height: 22px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 12H5'/%3E%3Cpath d='M12 19l-7-7 7-7'/%3E%3C/svg%3E")
    center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 12H5'/%3E%3Cpath d='M12 19l-7-7 7-7'/%3E%3C/svg%3E")
    center / contain no-repeat;
}

.screen-header .title {
  flex: 1;
  min-width: 0;
  font-size: var(--type-title);
  font-weight: 700;
  white-space: nowrap;
}

.screen-header .action {
  font-size: var(--type-body);
  color: var(--text-base);
}

.screen-header .action.muted {
  color: var(--text-muted);
}

/* ---- scroll body --------------------------------------------------------- */

.screen-body {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  /* 12px, not 6px, so a highlight on the first card has room for its 9px outset
     instead of being clipped against the screen top. */
  padding: 12px var(--list-gutter) var(--list-gutter);
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
  /* The offsetParent for a step's scroll-to-highlight on a plain screen. */
  position: relative;
}

.screen-body.tabs-inset {
  padding-bottom: 96px;
}

/* A docked footer holds the screen's main action at the foot of the phone, as
   ScrollScreen does. The body keeps that much room clear, so its last row can
   scroll out from under the button. */
.screen > .screen-footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  padding: 12px var(--list-gutter) 28px;
}

.screen-body.has-footer,
.screen-body.split.has-footer .scroll-region {
  padding-bottom: 100px;
}

/* A screen with a pinned dock (the calculator readout) splits into a fixed dock
   above and a region that scrolls beneath it. The dock never moves; each step
   sets the region's scroll offset, so one screen can be shown at different scroll
   positions. The screen gradient runs behind both, so there is no seam. */
.screen-body.split {
  padding: 0;
  gap: 0;
  overflow: hidden;
}

.screen-body.split .dock-region {
  flex-shrink: 0;
  padding: 12px var(--list-gutter) var(--card-gap);
}

.screen-body.split .scroll-region {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
  padding: 0 var(--list-gutter) var(--list-gutter);
}

/* ---- greeting / display heading ----------------------------------------- */

.greeting-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.greeting-row .muted {
  color: var(--text-muted);
}

.greeting-action {
  flex-shrink: 0;
  font-size: var(--type-body);
}

/* The app sets the greeting on Today 18 under the header's title row, closer
   than a first card sits. The row gives back the room the body keeps above a
   card, and it sets its own line height because the phone otherwise takes the
   host page's, which opens the gap back up. */
.screen-body > .greeting-row:first-child {
  margin-top: -12px;
  line-height: 1.35;
}

.display {
  font-size: var(--type-title);
  margin: 2px 0 6px;
}

/* ---- card ---------------------------------------------------------------- */

.card {
  background: var(--surface-dark-fill);
  border: 1px solid var(--separator);
  border-radius: 16px;
  padding: 14px 18px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.card.light {
  background: var(--surface-light-fill);
}

/* Flush list rows: no gap between children, so a row list is only spaced by each
   row's own padding and separator. */
.card.tight {
  gap: 0;
}

.card.frosted {
  border-radius: var(--frosted-card-radius);
}

.card.form {
  padding-top: 16px;
  padding-bottom: 16px;
  gap: 14px;
}

.card-heading {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  column-gap: 12px;
  justify-content: space-between;
}

.card-action {
  display: flex;
  align-items: center;
  min-height: 44px;
  max-width: 100%;
  font-size: var(--type-label);
  text-decoration: underline;
}

.card-action.muted {
  color: var(--text-muted);
}

.field-group {
  display: flex;
  flex-direction: column;
}

.hint.base {
  color: var(--text-base);
}

.result.label {
  font-size: var(--type-label);
}

.section-title {
  font-size: var(--type-heading);
}

.block {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.state-label {
  font-size: var(--type-body);
}

.state-label.danger {
  color: var(--text-danger);
}

.state-label.bold {
  font-weight: 700;
}

.hint {
  font-size: var(--type-label);
  color: var(--text-muted);
}

/* ---- field row (FieldValueRow / StickyField) ---------------------------- */

.field {
  padding: 12px 0;
  border-bottom: 1px solid var(--separator);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.field.compact {
  padding: 6px 0;
}

.field.no-sep {
  border-bottom: 0;
}

.field-label {
  font-size: var(--type-label);
  color: var(--text-muted);
}

.field-line {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 24px;
}

/* The app's switch keeps a 44 point touch target, which sets the row's height. */
.toggle-row {
  justify-content: space-between;
  min-height: 44px;
}

.field-value {
  flex: 1;
  font-size: var(--type-body);
  color: var(--text-base);
}

.field-value.placeholder {
  color: var(--text-muted);
}

.field-unit {
  font-size: var(--type-body);
  color: var(--text-muted);
}

.field-action {
  padding-left: 10px;
  font-size: var(--type-label);
  color: var(--text-muted);
  flex-shrink: 0;
}

.readonly-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.readonly-row .label,
.readonly-row .value {
  font-size: var(--type-body);
}

.readonly-row .label {
  color: var(--text-muted);
}

.warning {
  font-size: var(--type-label);
  color: var(--text-danger);
}

/* Label-left, value-right row, as on the protocol detail and settings screens. */
.detail-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  border-bottom: 1px solid var(--separator);
}

.detail-row.no-sep {
  border-bottom: 0;
}

/* A dose row and the draw panel under it share one hairline. */
.detail-group {
  border-bottom: 1px solid var(--separator);
}

.detail-group.no-sep {
  border-bottom: 0;
}

.detail-draw {
  padding: 2px 0 10px;
}

.detail-row .k {
  font-size: var(--type-body);
  color: var(--text-muted);
}

.detail-row .v {
  font-size: var(--type-body);
  color: var(--text-base);
  text-align: right;
}

/* The line over the Compounds list: the count beside the sort control, which is
   the segmented control held to a fixed width (mirrors CompoundsInventory). */
.inv-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 42px;
  padding-top: 8px;
}

.inv-count {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--type-label);
  color: var(--text-muted);
}

.inv-sort {
  flex-shrink: 0;
  width: 184px;
}

/* Grouped inventory list: bold compound headers and item rows, packed tight so
   their hairlines separate them (mirrors InventorySectionHeader and VialListRow). */
.inventory {
  display: flex;
  flex-direction: column;
}

.inv-header {
  font-size: var(--type-body);
  font-weight: 700;
  padding: 20px 0 8px;
  border-bottom: 1px solid var(--separator);
}

.inv-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--separator);
}

.inv-motif {
  flex-shrink: 0;
  display: flex;
  color: var(--text-base);
}
.inv-motif svg {
  width: 28px;
  height: 42px;
}

.inv-left {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.inv-title {
  font-size: var(--type-label);
  line-height: 1.2;
}

.inv-sub {
  font-size: var(--type-label);
  line-height: 1.2;
  color: var(--text-muted);
}

.inv-value {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--type-label);
}
.inv-value.low {
  color: var(--border-danger);
}

/* History-style row: a date over a colored dot and a short line, with a chevron. */
.hist-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
}

.hist-main {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.hist-date {
  font-size: var(--type-body);
}

.hist-sub {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--type-label);
  color: var(--text-muted);
}

.dot {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--adherence-success);
}

/* The day heading of a date-grouped history list (DaySectionHeader.tsx): a bold
   date with a muted tally at the far end. Its rules run to the screen edge. The
   one above is the heading's own, and the one below stands for the rule the app
   draws along the top of the day's first row. */
.day-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 calc(-1 * var(--list-gutter));
  padding: 28px var(--list-gutter) 8px;
  border-top: 1px solid var(--separator);
  border-bottom: 1px solid var(--separator);
}

.day-header.first {
  border-top: 0;
}

.day-header.tap::after {
  inset: -8px 6px;
}

.day-header-title {
  min-width: 0;
  overflow: hidden;
  font-size: var(--type-body);
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.day-header-count {
  flex-shrink: 0;
  font-size: var(--type-tab);
  color: var(--text-muted);
}

/* Standard "interact with this" highlight: a rounded rectangle drawn just outside
   the element, so it reads as an annotation over the screenshot rather than a UI
   focus state. Add `tap` to any element; recolor per shot with --tap-color. */
.tap {
  position: relative;
}

.tap::after {
  content: "";
  position: absolute;
  inset: -9px;
  border: 3px solid var(--tap-color, #ff3d7f);
  border-radius: 14px;
  pointer-events: none;
}

/* A stack row can be bled to the screen edge, so hold the box sides inside the
   frame instead of letting the outset clip against it. */
.stack-row.tap::after {
  inset: -8px 6px;
}

/* A bordered option card with a title, a description, and an example line, as on
   the "What do you have?" supply picker. */
.list-prompt {
  font-size: var(--type-heading);
  color: var(--text-base);
}

.select-card {
  border: 1px solid var(--separator);
  border-radius: 16px;
  padding: 16px 18px;
  background: var(--surface-dark-fill);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.select-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.select-title {
  font-size: var(--type-heading);
  font-weight: 700;
}

.select-desc {
  font-size: var(--type-body);
  color: var(--text-muted);
}

.select-eg {
  font-size: var(--type-label);
  color: var(--text-muted);
  opacity: 0.75;
}

/* Toggle mirroring the app's AppSwitch. Off by default; add `on` for the on
   state. The on state is a subtle dark track with a white thumb, not green. */
.switch {
  position: relative;
  width: 52px;
  height: 30px;
  flex-shrink: 0;
  border-radius: 15px;
  background: var(--surface-light-fill);
  border: 1px solid var(--separator);
}

.switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 3px;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: var(--text-muted);
  opacity: 0.62;
}

.switch.on {
  background: var(--surface-dark-fill);
  border-color: var(--text-muted);
}

.switch.on::after {
  left: auto;
  right: 3px;
  background: var(--text-base);
  opacity: 1;
}

/* A floating action-sheet menu inside a .screen. It sits inset from the screen
   edges with rounded corners and a soft shadow, and does not dim the screen
   behind it. The side padding keeps a tap ring on an option from clipping. */
.sheet {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 10px;
  /* Bottom room so a highlight on the last option is not clipped by the sheet. */
  padding: 0 12px 10px;
  background: var(--sheet-opaque-fill);
  border-radius: 22px;
  overflow: hidden;
  color: var(--text-base);
  box-shadow: 0 10px 44px rgba(0, 0, 0, 0.5);
}

.sheet-title {
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  padding: 13px;
}

.sheet.gradient {
  padding: 0 20px 20px;
  background: var(--panel-gradient);
  border-radius: var(--frosted-card-radius);
}

.sheet-heading {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 0;
  font-size: var(--type-heading);
  font-weight: 700;
}

.sheet-heading > :first-child {
  flex: 1;
}

.sheet-close {
  color: var(--text-muted);
  font-size: var(--type-body);
  font-weight: 400;
  flex-shrink: 0;
}

.sheet.gradient .sheet-option {
  padding: 12px 0;
  font-size: var(--type-body);
}

.sheet.gradient .sheet-option:first-child {
  border-top: 0;
}

.sheet.gradient .sheet-children {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 12px;
}

.sheet-option {
  padding: 13px 8px;
  font-size: var(--type-reading);
  border-top: 1px solid var(--separator);
}
.sheet-option.selected {
  background: var(--surface-light-selected);
}
.sheet-option.disabled .sheet-option-label {
  color: var(--text-muted);
}
.sheet-sub {
  margin-top: 3px;
  font-size: 12px;
  color: var(--text-muted);
}
.sheet-sub.low {
  color: var(--border-danger);
}

.sheet-done {
  text-align: center;
  padding: 14px;
  font-size: var(--type-body);
  font-weight: 600;
  border-top: 1px solid var(--separator);
}

/* Uppercase group label inside a screen, as on the compound picker sections. */
.group-label {
  font-size: var(--type-label);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}

/* A tappable list row, as in the compound picker. */
.pick-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 0;
  font-size: var(--type-body);
}

/* A neutral pill, as the "Custom" tag on a compound-picker result. */
.badge.neutral {
  background: var(--surface-light-selected);
}

.pick-row + .pick-row {
  border-top: 1px solid var(--separator);
}

/* The search field over the compound list. The app draws it with the prominent
   TextField, a dark blurred field with no icon. */
.search-dock {
  display: flex;
  align-items: center;
  padding: 16px 20px;
  border-radius: 18px;
  background: var(--surface-dark-selected);
  backdrop-filter: blur(24px);
  border: 1px solid var(--separator);
  color: var(--text-muted);
  font-size: var(--type-body);
}

/* Empty state, as on the Stack tab with no protocols. Every empty screen in the
   app sets a medium title over a muted sentence at most 320 wide, with its
   button 28 below the sentence. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 8px;
  padding: 40px 0 24px;
}

.empty-title {
  font-size: var(--type-title);
  font-weight: 500;
  text-wrap: balance;
}

.empty-body {
  font-size: var(--type-body);
  color: var(--text-muted);
  max-width: 320px;
}

.empty .btn {
  margin-top: 20px;
  min-width: 180px;
}

/* The ghost rows EmptyStateSkeleton.tsx draws under an empty state, 40 below
   whatever comes last and fading as they recede. */
.empty-skeleton {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 32px;
}

.empty-skeleton .card {
  gap: 8px;
  padding: 16px 18px;
}

.skeleton-bar {
  display: block;
  height: 14px;
  border-radius: 5px;
  background: var(--surface-light-selected);
}

.skeleton-bar.title {
  height: 16px;
  border-radius: 6px;
}

/* Weekday picker row (Days frequency). */
.weekday {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.day-row {
  display: flex;
  gap: 6px;
}

.day {
  flex: 1;
  aspect-ratio: 1;
  border-radius: 8px;
  border: 1px solid var(--separator);
  background: var(--surface-light-fill);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--type-label);
}

.day.selected {
  background: var(--text-base);
  color: var(--text-inverse);
  border-color: var(--text-base);
}

.block-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 24px;
}

.block-head-title {
  font-size: var(--type-body);
  font-weight: 600;
  color: var(--text-base);
}

.block-head-action {
  font-size: var(--type-label);
  color: var(--text-base);
}

.day-shortcuts {
  display: flex;
  gap: 8px;
}

.day-shortcut {
  flex: 1;
  min-height: 34px;
  padding: 0 12px;
  border-radius: 8px;
  border: 1px solid var(--separator);
  background: var(--surface-light-fill);
  color: var(--text-base);
  font-size: var(--type-label);
  display: flex;
  align-items: center;
  justify-content: center;
}

.day-shortcut.selected {
  background: var(--surface-light-selected);
  border-color: var(--text-base);
}

/* Nested titration step group: a bordered box with a header, a remove control,
   and field rows. */
.step-group {
  border: 1px solid var(--separator);
  border-radius: 8px;
  padding: 8px 12px;
  background: var(--surface-light-fill);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.step-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.step-group-title {
  font-size: var(--type-body);
  font-weight: 600;
}

.minus {
  position: relative;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  border-radius: 999px;
  border: 1.5px solid var(--text-muted);
}

.minus::after {
  content: "";
  position: absolute;
  left: 6px;
  right: 6px;
  top: 50%;
  height: 1.5px;
  background: var(--text-muted);
  transform: translateY(-50%);
}

.add-link {
  text-align: center;
  padding: 6px;
  font-size: var(--type-body);
  color: var(--text-base);
}

.add-link.left {
  text-align: left;
  padding-left: 0;
  padding-right: 0;
}

/* chevron: two borders rotated, matching the 14px muted glyph at 0.6 opacity */
.chevron {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(-45deg);
  opacity: 0.6;
}

/* A protocol color swatch, sits before the chevron in a Color row. */
.color-dot {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  border-radius: 999px;
}

/* ---- segmented control --------------------------------------------------- */

.segmented {
  display: flex;
  gap: 3px;
  padding: 3px;
  border-radius: 16px;
  background: var(--surface-light-fill);
  border: 1px solid var(--separator);
}

.segmented .seg {
  flex: 1;
  min-height: 36px;
  border-radius: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--type-label);
  color: var(--text-base);
  text-align: center;
}

.segmented .seg.selected {
  background: var(--text-base);
  color: var(--text-inverse);
}

/* ---- single-select button group ----------------------------------------- */

.choice-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.choice {
  min-height: 40px;
  padding: 0 16px;
  border-radius: 12px;
  border: 1px solid var(--separator);
  background: transparent;
  color: var(--text-base);
  font-size: var(--type-label);
  display: flex;
  align-items: center;
  justify-content: center;
}

.choice.selected {
  background: var(--text-base);
  color: var(--text-inverse);
  border-color: transparent;
}

/* ---- check-select list --------------------------------------------------- */

.checklist {
  display: flex;
  flex-direction: column;
}

.checklist .opt {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
}

.checklist .opt + .opt {
  border-top: 1px solid var(--separator);
}

.check-circle {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 999px;
  border: 1.5px solid var(--separator);
  background: var(--surface-light-fill);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  line-height: 1;
  color: transparent;
}

.check-circle.on {
  border-color: var(--text-base);
  background: var(--surface-light-selected);
  color: var(--text-base);
}

.opt-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.opt-title {
  font-size: var(--type-body);
  font-weight: 700;
}

.opt-desc {
  font-size: var(--type-label);
  color: var(--text-muted);
}

/* ---- badge --------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  border-radius: 6px;
  padding: 4px 8px;
  font-size: 10px;
  font-weight: 500;
  color: var(--text-base);
}

.badge.success {
  background: var(--badge-success-fill);
}
.badge.attention {
  background: var(--badge-attention-fill);
}
.badge.warning {
  background: var(--badge-warning-fill);
}
.badge.primary {
  background: var(--badge-primary-fill);
}
.badge.tinted {
  background: var(--badge-tinted-fill);
  border: 1px solid var(--badge-tinted-border);
  padding: 3px 7px;
}
.badge.solid {
  background: var(--badge-solid-fill);
  color: var(--badge-solid-label);
}
.badge.beta {
  background: var(--badge-beta-fill);
  border: 1px solid var(--badge-beta-border);
  color: var(--badge-beta-label);
  padding: 3px 7px;
}

/* ---- button -------------------------------------------------------------- */

.btn {
  min-height: 48px;
  padding: 0 18px;
  border-radius: 16px;
  border: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: inherit;
  font-size: var(--type-body);
  font-weight: 500;
}

.btn.full {
  width: 100%;
}

.btn.center {
  align-self: center;
}

.btn.solid {
  background: var(--button-solid-fill);
  color: var(--button-solid-label);
}

.btn.soft {
  background: var(--button-soft-fill);
  color: var(--button-soft-label);
}

.btn.outline {
  background: transparent;
  border: 1px solid var(--button-outline-border);
  color: var(--button-outline-label);
}

/* ---- floating tab bar ---------------------------------------------------- */

.tabbar {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 20px;
  height: 60px;
  border-radius: 28px;
  background: var(--panel-fill);
  border: 1px solid var(--separator);
  backdrop-filter: blur(24px);
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 0 8px;
}

.tabbar .tab {
  font-size: var(--type-tab);
  color: var(--tab-bar-muted);
}

.tabbar .tab.active {
  color: var(--tab-bar-base);
}

/* ---- adherence ring (Today) --------------------------------------------- */

.ring {
  width: 56px;
  height: 56px;
  flex-shrink: 0;
  border-radius: 999px;
  display: grid;
  place-items: center;
  font-size: var(--type-label);
  background: conic-gradient(var(--adherence-success) var(--pct, 80%), var(--separator) 0);
}

.ring .inner {
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: var(--surface-dark-fill);
  display: grid;
  place-items: center;
}

/* ---- chevron directions -------------------------------------------------- */
.chevron.up {
  transform: rotate(-135deg);
}
.chevron.down {
  transform: rotate(45deg);
}

/* ---- stack (protocol list) ----------------------------------------------- */
.stack-list {
  display: flex;
  flex-direction: column;
}

.stack-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 24px;
  border-bottom: 1px solid var(--separator);
}

.stack-row:last-child {
  border-bottom: 0;
}

.stack-row.paused {
  opacity: 0.45;
}

/* Color rail flush to the screen edge, full row height, only on colored rows. */
.stack-rail {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 5px;
}

.stack-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.stack-name {
  font-size: var(--type-body);
  font-weight: 700;
}

.stack-sub {
  font-size: var(--type-body);
  color: var(--text-muted);
}

/* The units to draw, in the dose line's color because it is the thing to act on.
   The multi-strength note recedes to muted, as the app draws its caveat. */
.stack-draw {
  font-size: var(--type-body);
  color: var(--text-base);
}

.stack-draw.muted {
  color: var(--text-muted);
}

/* The 1 mL ruler under the units, no 0 and 100 labels, as ProtocolRow draws it with
   showLimits off. The wrapper owns the air above and below, so the shared ruler
   margin is zeroed here or the two would stack. */
.stack-ruler {
  margin: 6px 0;
}

.stack-ruler .ruler-svg {
  height: 18px;
  margin: 0;
}

.stack-adherence {
  font-size: var(--type-body);
  color: var(--text-muted);
}

/* The end-date countdown, one size with the rest and set apart only by the danger
   color, not weight. */
.stack-countdown {
  font-size: var(--type-body);
  color: var(--text-danger);
}

.reorder {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  border: 1px solid var(--separator);
  border-radius: 12px;
  overflow: hidden;
}

.reorder-btn {
  width: 42px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.reorder-btn + .reorder-btn {
  border-top: 1px solid var(--separator);
}

/* ---- today dose card ----------------------------------------------------- */
/* A dose card that is settled (logged, skipped, or missed) fades back, as
   doseCardStyles.rowDim does. */
.card.dim {
  opacity: 0.45;
}

/* A card that carries a protocol color sets it inline as its border and wash.
   Over the wash the app prints the dose line in the base text color instead of
   the muted one. */
.card.tinted .today-dose {
  color: var(--text-base);
}

.today-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.today-time {
  font-size: var(--type-label);
  color: var(--text-muted);
}

.today-name {
  font-size: var(--type-title);
  font-weight: 700;
}

.today-dose {
  font-size: var(--type-body);
  color: var(--text-muted);
}

/* DoseDrawHint prints this line under the dose. The spaces have to survive,
   because the app sets the units and the strength in one run of text two spaces
   apart. */
.today-draw {
  border-radius: 8px;
  padding: 8px 12px;
  background: var(--surface-light-fill);
  font-size: var(--type-body);
  white-space: pre-wrap;
}

.today-draw-units {
  font-weight: 700;
}

.today-draw-detail {
  color: var(--text-muted);
}

/* The compact ruler under the units, half the height of the Measure ruler. Its
   scale reads at the app's tab size in the base color, as SyringeRuler draws it. */
.draw-ruler .ruler-svg {
  height: 18px;
  margin: 6px 0 0;
}

.draw-ruler .ruler-scale {
  font-size: var(--type-tab);
  color: var(--text-base);
}

/* ---- syringe hint / draw ruler ------------------------------------------- */
.syringe-head {
  display: flex;
  gap: 16px;
}

.syringe-head > div {
  flex: 1;
}

.syringe-val {
  font-size: var(--type-body);
  font-weight: 700;
}

/* Ported from the app's SyringeRuler: a shaded draw region, a baseline axis, and
   major/minor ticks, stretched to width. currentColor is the base ink. */
.ruler-svg {
  display: block;
  width: 100%;
  height: 40px;
  overflow: visible;
  color: var(--text-base);
  margin: 8px 0 2px;
}

.ruler-scale {
  display: flex;
  justify-content: space-between;
  font-size: var(--type-label);
  color: var(--text-muted);
}

/* ---- injection sites ----------------------------------------------------- */
.sites-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.help-icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  border-radius: 999px;
  border: 1.5px solid var(--text-muted);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
}

/* The recent sites row over the site grid (RecentInjectionSites.tsx): a small
   caption over one primary Badge per injection, wrapping at the card's edge. */
.chips {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.chips-caption {
  font-size: var(--type-tab);
  color: var(--text-muted);
}

.chips-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.chips-row .badge {
  flex-shrink: 0;
  white-space: nowrap;
}

.site-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.site-card {
  border: 1px solid var(--separator);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.site-card.selected {
  border-color: var(--text-base);
}

.site-label {
  font-size: var(--type-body);
  font-weight: 700;
  line-height: 1.25;
}

.site-status {
  font-size: var(--type-label);
  color: var(--text-muted);
}

/* The "Next" rotation hint on the suggested site: a small, tight, filled chip. */
.site-badge {
  align-self: flex-start;
  font-size: var(--type-tab);
  font-weight: 600;
  line-height: 1.3;
  background: var(--text-base);
  color: var(--text-inverse);
  border-radius: 4px;
  padding: 1px 6px;
  margin-top: 2px;
}

/* ---- inventory motifs ---------------------------------------------------- */
.motif {
  color: var(--text-base);
}

.motif.low {
  color: var(--border-danger);
}

/* ---- vial-detail hero ---------------------------------------------------- */
.pen-dose {
  display: flex;
  align-items: center;
  gap: 16px;
}

.pen-dose-figures {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.pen-dose-label {
  font-size: var(--type-label);
  color: var(--text-muted);
}

.pen-dose-value {
  font-size: var(--type-heading);
  font-weight: 500;
}

.pen-dose-art {
  width: 60px;
  flex-shrink: 0;
}

.pen-dose-art svg {
  display: block;
  width: 60px;
  height: 78px;
}

.pen-dose .low {
  color: var(--border-danger);
}

.vial-hero {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 22px;
}
.vial-hero-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.vial-hero-art {
  flex-shrink: 0;
  color: var(--text-base);
}
.vial-hero-art.low {
  color: var(--border-danger);
}
.vial-hero.dimmed {
  opacity: 0.55;
}
.vial-hero-status {
  font-size: var(--type-label);
  color: var(--text-muted);
  margin-top: 2px;
}

/* ---- Today active-inventory rail ---------------------------------------- */
.inventory-rail {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rail-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.rail-head-title {
  font-size: var(--type-heading);
  font-weight: 700;
}
.rail-count {
  font-size: var(--type-label);
  color: var(--text-muted);
}
.rail-low {
  color: var(--border-danger);
}
/* The rail bleeds by the screen gutter, as TodayInventoryRail does, so a card cut
   by the edge runs off the screen instead of stopping short of it. */
.rail-scroll {
  display: flex;
  gap: 12px;
  overflow: hidden;
  margin: 0 calc(-1 * var(--list-gutter));
  /* Vertical room so a highlighted card's tap box is not clipped by overflow. */
  padding: 12px var(--list-gutter);
}
.rail-card {
  flex-shrink: 0;
  width: 190px;
  background: var(--surface-light-fill);
  border: 1px solid var(--separator);
  border-radius: 18px;
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  line-height: 1.2;
}
.rail-card.low {
  border-color: var(--border-danger);
}
.rail-motif {
  flex-shrink: 0;
  display: flex;
  color: var(--text-base);
}
.rail-motif svg {
  width: 36px;
  height: 54px;
}
.rail-copy {
  flex: 1;
  min-width: 0;
}
.rail-card.low .rail-motif {
  color: var(--border-danger);
}
.rail-compound {
  font-weight: 700;
  font-size: var(--type-label);
}
.rail-title {
  font-size: var(--type-label);
  margin-top: 2px;
  letter-spacing: 0.4px;
}
.rail-summary {
  font-size: var(--type-label);
  margin-top: 3px;
  letter-spacing: 0.4px;
}
.rail-summary.low {
  color: var(--border-danger);
}

/* ---- source rail --------------------------------------------------------- */
/* The Taken from picker on the dose screens (DoseSourceRail). Low shows only on
   the count, and a split numbers its two vials with a round badge set concentric
   with the card's corner. */
.source-rail {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.source-scroll {
  display: flex;
  gap: 12px;
  overflow: hidden;
  margin: 0 -20px;
  /* Vertical room so a highlighted card's tap box is not clipped by overflow. */
  padding: 12px 20px;
}
.source-card {
  position: relative;
  flex-shrink: 0;
  width: 132px;
  min-height: 152px;
  box-sizing: border-box;
  background: var(--surface-light-fill);
  border: 1px solid var(--border-base);
  border-radius: 18px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}
.source-card.selected {
  background: var(--surface-light-selected);
  border-color: var(--text-base);
}
.source-card.blocked {
  opacity: 0.45;
}
.source-motif {
  color: var(--text-base);
  height: 68px;
}
.source-motif svg {
  height: 68px;
  width: auto;
}
.source-order {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  border-radius: 12px;
  background: var(--text-base);
  color: var(--text-inverse);
  font-size: var(--type-label);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.source-title {
  font-weight: 700;
  font-size: var(--type-label);
  margin-top: 8px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.source-sub,
.source-amount {
  font-size: var(--type-label);
  letter-spacing: 0.4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.source-sub {
  margin-top: 1px;
  color: var(--text-muted);
}
.source-amount {
  margin-top: 1px;
}
.source-amount.low {
  color: var(--text-danger);
}
.source-picked {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.source-picked-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.source-picked-title {
  font-size: var(--type-body);
}
.source-picked-sub {
  font-size: var(--type-label);
  color: var(--text-muted);
}
.source-note {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px solid var(--separator);
}
.source-note-title {
  font-size: var(--type-label);
  font-weight: 700;
}
.source-note-hint {
  font-size: var(--type-label);
}
.source-empty {
  font-size: var(--type-label);
  color: var(--text-muted);
}

/* ---- danger zone --------------------------------------------------------- */
/* The destructive form-action card: same shell as .form-action, with a warning
   icon and a rule under the title. Keep it in step with .form-action above. */
.danger-zone {
  background: var(--surface-light-fill);
  border: 1px solid var(--separator);
  border-radius: 16px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.danger-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--type-label);
  letter-spacing: 0.5px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--separator);
}

.danger-head svg {
  flex-shrink: 0;
}

.danger-body {
  font-size: var(--type-label);
  color: var(--text-muted);
  line-height: 1.5;
}

.danger-action {
  font-size: var(--type-heading);
  min-height: 44px;
  display: flex;
  align-items: center;
}

/* ---- action / entry card ------------------------------------------------- */
.action-card {
  display: flex;
  align-items: center;
  gap: 14px;
  border: 1px solid var(--separator);
  border-radius: 16px;
  padding: 16px 18px;
}

.action-card.danger {
  border-color: var(--border-danger);
}

.action-icon {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: 12px;
  background: var(--surface-light-fill);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-base);
}

.action-card.danger .action-icon {
  background: var(--field-error-fill);
  color: var(--adherence-danger);
}

.action-icon svg {
  width: auto;
  height: 28px;
}

.action-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.action-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.action-title {
  font-size: var(--type-body);
  font-weight: 700;
}

/* A hairline between screen sections (the nav cards under the dose list on Today). */
.divider {
  height: 1px;
  /* An empty flex child collapses under flex-shrink when the screen overflows
     (a bottom-cropped screen does), so it must hold its 1px. */
  flex-shrink: 0;
  /* Stronger than a card's inner --separator hairline: a divider sits on the
     screen background between blocks, where 0.15 white all but disappears. */
  background: rgba(255, 255, 255, 0.3);
  margin: 8px 0;
}

.action-sub {
  font-size: var(--type-label);
  color: var(--text-muted);
  line-height: 1.35;
}

/* ---- note, stat, button bar ---------------------------------------------- */
.note {
  font-size: var(--type-label);
  color: var(--text-muted);
  line-height: 1.4;
}

.note.danger {
  color: var(--text-danger);
}

.note.muted {
  color: var(--text-muted);
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.stat-label {
  font-size: var(--type-label);
  color: var(--text-muted);
}

.stat-value {
  font-size: var(--type-heading);
  font-weight: 700;
}
.stat-row {
  display: flex;
}
.stat-cell {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.stat-cell + .stat-cell {
  border-left: 1px solid var(--separator);
  padding-left: 16px;
}
.stat-cell-value {
  font-size: var(--type-reading);
  font-weight: 700;
}

.button-bar {
  display: flex;
  gap: 12px;
}

.button-bar .btn {
  flex: 1;
}

/* A mid-card section title starts a new group, so it carries a divider above it. */
.card > .section-title:not(:first-child) {
  border-top: 1px solid var(--separator);
  padding-top: 14px;
  margin-top: 8px;
}

/* A sentence line with one bold span, as on "Scheduled for Thu, Jan 8 at 8am". */
.sched {
  font-size: var(--type-body);
  color: var(--text-muted);
}

.sched-strong {
  color: var(--text-base);
  font-weight: 700;
}

/* ---- record heading (bold name over muted lines) ------------------------- */
.heading {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.heading-title {
  font-size: var(--type-title);
  font-weight: 700;
}

.heading-line {
  font-size: var(--type-body);
  color: var(--text-muted);
}

/* ---- numeric keypad (KeyboardStickyInput + NumericKeypad) ---------------- */
.screen > .keypad {
  position: absolute;
  bottom: 10px;
  left: 10px;
  right: 10px;
}

.keypad {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.keypad-input {
  border-radius: 22px;
  padding: 14px 18px;
  background: var(--sheet-opaque-fill);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.keypad-input > .segmented {
  margin-top: 10px;
}

/* A field with one unit names it where the unit choices would sit. */
.keypad-unit {
  margin-top: 10px;
  font-size: var(--type-label);
  color: var(--text-muted);
}

.keypad-label {
  font-size: var(--type-label);
  color: var(--text-muted);
}

.keypad-value {
  font-size: var(--type-title);
  font-weight: 400;
  display: flex;
  align-items: center;
}

/* A zero-width character holds one line of type, so the box is the same height
   before the first digit as after it. */
.keypad-value::before {
  content: "\200b";
}

.caret {
  display: inline-block;
  width: 2px;
  height: 26px;
  margin-left: 2px;
  background: var(--text-base);
}

.keypad-actions {
  display: flex;
  margin: 14px -18px 0;
  padding: 0 18px;
  border-top: 1px solid var(--separator);
  font-size: var(--type-label);
  color: var(--text-base);
}

.keypad-actions > span {
  flex: 1;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.numpad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  padding: 6px;
  border-radius: 22px;
  background: var(--sheet-opaque-fill);
}

.numkey {
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  font-size: var(--type-title);
  color: var(--text-base);
}

.numkey svg {
  width: 24px;
  height: 24px;
}

/* ---- dose-history calendar ----------------------------------------------- */
.calendar {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.cal-title {
  font-size: var(--type-heading);
}

.cal-nav {
  font-size: var(--type-title);
  color: var(--text-muted);
}

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.cal-weekday {
  text-align: center;
  font-size: var(--type-label);
  color: var(--text-muted);
  padding-bottom: 4px;
}

.cal-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 4px 0;
  min-height: 42px;
}

.cal-day {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  font-size: var(--type-label);
}

.cal-day.today {
  background: var(--text-base);
  color: var(--text-inverse);
  font-weight: 700;
}

.cal-day.muted {
  color: var(--text-muted);
}

.cal-dots {
  display: flex;
  gap: 3px;
  height: 6px;
}

.cal-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
}

/* Trailing time and chevron on a history / dose row. */
.hist-end {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.hist-time {
  font-size: var(--type-label);
  color: var(--text-muted);
}

/* ---- large input field (StickyField numeric entry) ---------------------- */
.field.big {
  padding: 10px 0;
}

.field.big .field-value {
  font-size: var(--type-title);
}

/* An empty input reads as a normal placeholder, not a huge value. */
.field.big .field-value.placeholder {
  font-size: var(--type-body);
}

.field.big .field-unit {
  font-size: var(--type-body);
}

/* ---- reconstitution calculator readout ---------------------------------- */
.measure {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.measure-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.measure-units {
  font-size: var(--type-title);
  font-weight: 700;
}

.measure-units.editable {
  text-decoration: underline;
}

.measure-vol {
  font-size: var(--type-body);
  color: var(--text-muted);
}

.measure-syringe {
  text-align: right;
}

.syringe-pick {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  font-size: var(--type-body);
}

.syringe-pick > span {
  text-decoration: underline;
}

.syringe-pick > svg {
  color: var(--text-muted);
  opacity: 0.6;
}

.measure-spec {
  font-size: var(--type-label);
  color: var(--text-muted);
}

.measure-slider {
  position: relative;
  height: 20px;
  margin-top: 2px;
}

.measure-slider::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 9px;
  height: 2px;
  border-radius: 999px;
  background: var(--separator);
}

.slider-handle {
  position: absolute;
  top: 0;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  background: var(--text-base);
  transform: translateX(-50%);
}

/* A centered computed readout under the calculator inputs. */
.result {
  text-align: center;
  font-size: var(--type-heading);
  font-weight: 700;
}

/* A centered tappable line. */
.link {
  text-align: center;
  font-size: var(--type-body);
  color: var(--text-muted);
}

.btn.ghost {
  background: transparent;
  color: var(--button-ghost-label);
}

/* A titled card that explains one action and offers it as a text link beneath the
   copy (FormActionCard: unskip a dose, undo a log). The title is a small ruled
   heading, the body is label text, and the action reads at heading size. */
.form-action {
  background: var(--surface-light-fill);
  border: 1px solid var(--separator);
  border-radius: 16px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.form-action-head {
  font-size: var(--type-label);
  letter-spacing: 0.5px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--separator);
}

.form-action-body {
  font-size: var(--type-label);
}

.form-action-link {
  font-size: var(--type-heading);
  min-height: 44px;
  display: flex;
  align-items: center;
}

/* ---- Upcoming card (TodayUpcomingCard) ---------------------------------- */
/* The rows bleed past the card's gutter so their rules meet its inner border,
   and the card clips them to its rounded corners. */
/* Clipping makes the card shrinkable inside the screen's column, so it would
   collapse to a sliver on a screen taller than the phone. It must hold its size. */
.card.upcoming {
  flex-shrink: 0;
  gap: 0;
  overflow: hidden;
}

.upcoming-head {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-bottom: 14px;
}

.upcoming-day {
  font-size: var(--type-display);
  font-weight: 700;
}

.upcoming-date-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.upcoming-date {
  font-size: var(--type-body);
}

.upcoming-count {
  flex-shrink: 0;
  font-size: var(--type-tab);
  color: var(--text-muted);
}

.upcoming-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 56px;
  margin: 0 -18px;
  padding: 10px 16px 10px 18px;
  border-top: 1px solid var(--separator);
  position: relative;
}

.upcoming-row:last-child {
  border-bottom: 1px solid var(--separator);
}

/* ProtocolColorEdge draws the protocol's color down the leading edge of its row,
   from the rule above the row to the rule below it. */
.upcoming-edge {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 5px;
}

/* ---- Your Sky doorway (SkyDoorway) -------------------------------------- */
.sky-doorway {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 28px 24px;
}

.sky-doorway-title {
  font-size: var(--type-title);
  font-weight: 700;
}

.sky-doorway-week {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--type-body);
  font-weight: 500;
  color: var(--text-muted);
}

/* ---- Adherence card (ProtocolPerformanceCard, AdherenceRing) ------------- */
.adherence {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 10px;
}

.adherence-summary {
  display: flex;
  align-items: center;
  gap: 18px;
}

.adherence-ring {
  position: relative;
  flex-shrink: 0;
  width: 108px;
  height: 108px;
}

.adherence-percent {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: var(--type-title);
}

.adherence-stats {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.adherence-stat {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--type-body);
}

.adherence-dot {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  border-radius: 16px;
}

.adherence-weeks {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--separator);
}

.adherence-week {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 36px;
}

.adherence-week-label {
  font-size: var(--type-body);
  color: var(--text-muted);
}

.adherence-days {
  display: flex;
  gap: 3px;
}

/* A fixed slot per day, so the outline on today never shifts the row. */
.adherence-slot {
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border: 1.5px solid transparent;
  border-radius: 36px;
}

.adherence-slot.today {
  border-color: var(--text-base);
}

.adherence-weekday {
  font-size: var(--type-tab);
  color: var(--text-muted);
}

.adherence-more {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 32px;
  padding-top: 2px;
  font-size: var(--type-label);
  color: var(--text-muted);
}

/* ---- weekly check and symptoms ------------------------------------------- */

/* The weekly check on Today (WeeklyCheckInCard.tsx). It takes the dose card's
   title and line. Its buttons share one row the way a dose card's do. */
.today-dose.base {
  color: var(--text-base);
}

.check-in-actions {
  display: flex;
  gap: 12px;
  padding-top: 4px;
}

.check-in-actions .btn {
  flex: 1;
}

.btn.disabled {
  opacity: 0.5;
}

/* CheckRow.tsx. The label leads and stays muted until its row is checked. */
.check-rows {
  display: flex;
  flex-direction: column;
}

.check-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
}

.check-row + .check-row,
.check-rows.ruled .check-row:first-child {
  border-top: 1px solid var(--separator);
}

.check-row-label {
  flex: 1;
  font-size: var(--type-body);
  color: var(--text-muted);
}

.check-row.checked .check-row-label {
  color: var(--text-base);
}

/* DaysStrip.tsx. A marked day is filled and only today wears a ring, which
   keeps the two from reading alike. */
.days-strip {
  display: flex;
  flex-direction: column;
}

.strip-row {
  display: flex;
}

.strip-weekday {
  flex: 1;
  padding: 4px 0;
  text-align: center;
  font-size: var(--type-tab);
  color: var(--text-muted);
}

.strip-cell {
  flex: 1;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.strip-day {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: var(--type-label);
}

.strip-day.today {
  border-color: var(--text-base);
}

.strip-day.selected {
  background: var(--text-base);
  border-color: var(--text-base);
  color: var(--text-inverse);
}

.eyebrow {
  font-size: var(--type-tab);
  font-weight: 500;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--text-muted);
}

.prompt {
  font-size: var(--type-body);
}

.prompt-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.prompt-aside {
  flex-shrink: 0;
  font-size: var(--type-label);
  color: var(--text-muted);
}

.hint.body {
  font-size: var(--type-body);
}

/* A switch that stands alone on a screen, as Show on Today does on Symptoms. */
.toggle-titled {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.toggle-copy {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.toggle-title {
  font-size: var(--type-heading);
}

.toggle-detail {
  font-size: var(--type-label);
  color: var(--text-muted);
}

.taking-list {
  display: flex;
  flex-direction: column;
}

.taking-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 0;
  border-bottom: 1px solid var(--separator);
}

.taking-name {
  font-size: var(--type-body);
}

.taking-detail {
  font-size: var(--type-body);
  color: var(--text-muted);
}

/* The app's bottom sheet at full length (AppBottomSheet.tsx). The panel stops at
   86 percent of the screen and its body scrolls inside it from there. Its
   actions stay pinned under a hairline. A question sits 10 over its answer and
   24 under the answer before it. */
.sheet.paged {
  display: flex;
  flex-direction: column;
  max-height: calc(var(--screen-h, 852px) * 0.86);
  padding: 0;
}

.sheet.paged .sheet-heading {
  flex-shrink: 0;
  padding: 16px 20px 20px;
}

.sheet.paged .sheet-body {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

/* Scrolled all the way down, the body rests on its last row and the rows it
   has passed leave over the top. */
.sheet.paged .sheet-body.at-end {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.sheet.paged .sheet-body-inner {
  flex-shrink: 0;
  padding: 0 20px 20px;
}

.sheet.paged .sheet-children {
  gap: 10px;
  margin-top: 0;
}

.sheet.paged .sheet-children > .prompt,
.sheet.paged .sheet-children > .prompt-row {
  margin-top: 14px;
}

.sheet.paged .sheet-footer {
  flex-shrink: 0;
  padding: 12px 20px 20px;
  border-top: 1px solid var(--separator);
}
