/* ---------------------------------------------------------------------- */
/* Cards                                                                   */
/* ---------------------------------------------------------------------- */

.card {
  background-color: var(--color-card);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

.card--hero {
  border-radius: var(--radius-large);
  padding: var(--screen-padding);
}

.card--standard {
  padding: var(--screen-padding);
}

.card--compact {
  padding: var(--space-2);
  min-height: 52px;
}

.card--interactive {
  cursor: pointer;
  transition:
    transform var(--motion-fast) var(--ease-standard),
    filter var(--motion-fast) var(--ease-standard);
}

.card--interactive:active {
  transform: scale(0.99);
  filter: brightness(0.97);
}

/* ---------------------------------------------------------------------- */
/* Buttons                                                                 */
/* ---------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 44px;
  padding: 0 var(--screen-padding);
  border-radius: var(--radius-button);
  border: none;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition:
    background-color var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard),
    transform var(--motion-fast) var(--ease-standard);
}

.btn:disabled {
  cursor: not-allowed;
}

/* Background uses --color-primary-dark, not the lighter --color-primary:
   white text on the original #5A9BD5 only reached ~2.96:1. --color-primary
   itself stays reserved for decorative/non-textual uses. */
.btn--primary {
  height: 50px;
  background-color: var(--color-primary-dark);
  color: var(--color-on-primary);
}

.btn--primary:active {
  background-color: var(--ink-nav);
  transform: scale(0.99);
}

.btn--primary:disabled {
  background-color: var(--color-disabled);
  color: var(--color-text-muted);
  /* Slightly soften a full-width disabled action (e.g. "Add observation"
     before a rating is chosen) without losing a recognisable disabled look. */
  opacity: 0.7;
}

/* Text/border use --color-primary-dark: the original --color-primary text
   on white only reached ~2.96:1. */
.btn--secondary {
  height: 50px;
  background-color: var(--color-card);
  color: var(--color-primary-dark);
  border: 1px solid var(--color-primary-dark);
}

.btn--secondary:active {
  background-color: var(--color-surface-soft);
  transform: scale(0.99);
}

.btn--secondary:disabled {
  background-color: var(--color-card);
  color: var(--color-text-muted);
  border-color: var(--color-disabled);
}

/* Text uses --color-primary-dark: the original --color-primary text only
   reached ~2.96:1 against white/soft backgrounds. */
.btn--tertiary {
  height: 44px;
  padding: 0 var(--space-2);
  background-color: transparent;
  color: var(--color-primary-dark);
}

.btn--tertiary:active {
  color: var(--color-secondary);
  background-color: var(--color-surface-soft);
}

.btn--tertiary:disabled {
  color: var(--color-text-muted);
}

/* ---------------------------------------------------------------------- */
/* Input shell                                                             */
/* ---------------------------------------------------------------------- */

.input,
.select {
  display: block;
  width: 100%;
  min-height: 48px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-input);
  border: 1px solid var(--color-border);
  background-color: var(--color-card);
  color: var(--color-text);
  font-family: inherit;
  font-size: 16px;
}

.textarea {
  display: block;
  width: 100%;
  min-height: 96px;
  padding: var(--space-2);
  border-radius: var(--radius-input);
  border: 1px solid var(--color-border);
  background-color: var(--color-card);
  color: var(--color-text);
  font-family: inherit;
  font-size: 16px;
  line-height: 1.45;
  resize: vertical;
}

.input::placeholder,
.textarea::placeholder {
  color: var(--color-placeholder);
}

.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible {
  outline: none;
  border-color: var(--color-primary);
  /* D1: --focus-ring is --color-primary at 0.22 alpha (tokens.css). */
  box-shadow: 0 0 0 3px var(--focus-ring);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background-color: var(--color-surface-muted);
  color: var(--color-text-muted);
  border-color: var(--color-disabled);
}

/* ---------------------------------------------------------------------- */
/* Status badges                                                          */
/* ---------------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-0-5);
  height: 32px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background-color: var(--color-surface-soft);
  border-left: 3px solid var(--status-inactive);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-text);
  white-space: nowrap;
}

/* Text colour is --color-text (not the raw status hue) on all variants:
   status-success/status-danger text-on-tint fails WCAG AA (~2.1:1/~2.9:1
   against --color-surface-soft). Differentiation instead comes from the
   left accent bar + the distinct text label + (for success) the check
   icon — which also reads better for colour-blind users than relying on
   red/green hue alone. */
.badge--success {
  border-left-color: var(--status-success);
  color: var(--color-text);
}

.badge--warning {
  border-left-color: var(--status-warning);
  color: var(--color-text);
}

.badge--danger {
  border-left-color: var(--status-danger);
  color: var(--color-text);
}

.badge--inactive {
  border-left-color: var(--status-inactive);
  color: var(--color-text);
}

/* ---------------------------------------------------------------------- */
/* Completion indicators                                                   */
/* ---------------------------------------------------------------------- */

.completion-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}

.completion-dot--completed {
  background-color: var(--status-success);
  color: var(--color-on-primary);
}

.completion-dot--outstanding {
  background-color: transparent;
  border: 2px solid var(--status-inactive);
}

.completion-dot--in-progress {
  background: linear-gradient(90deg, var(--status-warning) 50%, transparent 50%);
  border: 2px solid var(--status-warning);
}

.completion-dot--not-applicable {
  background-color: var(--color-surface-muted);
  border: 2px solid var(--color-disabled);
  color: var(--color-text-muted);
}

/* ---------------------------------------------------------------------- */
/* Bottom navigation                                                       */
/* ---------------------------------------------------------------------- */

.bottom-nav {
  /* D1: a floating pill inset from the screen edges, in place of the old
     full-width bar. Fixed to the viewport; --bottom-nav-offset is the gap
     beneath it (plus the safe-area inset), and every "clear the nav"
     calculation in the app adds that offset (layout.css, .fab, .toast). */
  position: fixed;
  left: var(--space-2);
  right: var(--space-2);
  bottom: var(--bottom-nav-gap);
  z-index: 100;
  display: flex;
  align-items: center;
  height: var(--bottom-nav-height);
  padding: 0 var(--space-0-5);
  background-color: var(--ink-nav);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-floating);
}

/* A soft fade behind the floating nav, so content scrolling underneath the
   pill (and through the gap around it) dissolves into the page instead of
   showing its edges beside and below the nav. It never takes a tap. */
#bottom-nav-mount::before {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 99;
  height: calc(var(--bottom-nav-height) + var(--bottom-nav-gap) + var(--space-4));
  background: linear-gradient(to top, var(--color-bg), transparent);
  background: linear-gradient(to top, var(--color-bg) 0%, var(--color-bg) 40%, color-mix(in srgb, var(--color-bg) 0%, transparent) 100%);
  pointer-events: none;
}

@media (min-width: 480px) {
  .bottom-nav {
    left: 50%;
    right: auto;
    width: calc(480px - var(--space-4));
    transform: translateX(-50%);
  }
}

.bottom-nav__item {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 44px;
  min-height: 44px;
  height: calc(var(--bottom-nav-height) - var(--space-1));
  background: none;
  border: none;
  border-radius: var(--radius-pill);
  color: rgba(255, 255, 255, 0.72);
  font-family: inherit;
  cursor: pointer;
  transition:
    background-color var(--motion-standard) var(--ease-standard),
    color var(--motion-standard) var(--ease-standard);
}

.bottom-nav__icon svg {
  width: 22px;
  height: 22px;
}

.bottom-nav__label {
  font-size: 11px;
  font-weight: 500;
  line-height: 1.2;
  /* At large iOS text-zoom settings a label could otherwise wrap inside the
     nav's fixed height. Truncate instead of wrapping. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The active destination is a filled pill rather than a coloured label
   (colour is never the only cue: weight and the pill both change). White on
   the translucent pill over --ink-nav stays above 7:1. */
.bottom-nav__item--active {
  color: var(--color-on-photo);
  background-color: rgba(255, 255, 255, 0.14);
}

.bottom-nav__item--active .bottom-nav__label {
  font-weight: 600;
}

.bottom-nav__item--add {
  flex: none;
  width: 52px;
  height: 52px;
  min-height: 52px;
  margin: 0 var(--space-0-5);
  background-color: var(--color-accent);
  color: var(--ink-nav);
}

.bottom-nav__item--add .bottom-nav__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.bottom-nav__item--add .bottom-nav__icon svg {
  width: 24px;
  height: 24px;
}

.bottom-nav__item--add:active {
  background-color: var(--color-accent-pressed);
}

.bottom-nav__item:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* ---------------------------------------------------------------------- */
/* Floating action button                                                  */
/* ---------------------------------------------------------------------- */

.fab {
  position: fixed;
  right: var(--screen-padding);
  bottom: calc(var(--bottom-nav-height) + var(--bottom-nav-gap) + var(--space-1));
  z-index: 110;
  width: 60px;
  height: 60px;
  border-radius: var(--radius-pill);
  border: none;
  background-color: var(--color-accent);
  color: var(--color-secondary);
  box-shadow: var(--shadow-floating);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition:
    background-color var(--motion-fast) var(--ease-standard),
    transform var(--motion-fast) var(--ease-standard);
}

.fab:active {
  background-color: var(--color-accent-pressed);
  transform: scale(0.99);
}

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

/* Keep the FAB anchored to the centred shell's edge, not the browser window's */
@media (min-width: 480px) {
  .fab {
    right: calc((100vw - 480px) / 2 + var(--screen-padding));
  }
}

/* ---------------------------------------------------------------------- */
/* Toast (brief inline confirmation, e.g. "Saved ✓")                       */
/* ---------------------------------------------------------------------- */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--bottom-nav-height) + var(--bottom-nav-gap) + var(--space-3));
  transform: translateX(-50%) translateY(8px);
  max-width: calc(100% - var(--space-4));
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  background-color: var(--color-secondary);
  color: var(--color-on-primary);
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  box-shadow: var(--shadow-floating);
  opacity: 0;
  pointer-events: none;
  z-index: 200;
  transition:
    opacity var(--motion-standard) var(--ease-standard),
    transform var(--motion-standard) var(--ease-standard);
}

.toast--visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* A toast with an action (for example Undo) is tappable. */
.toast--has-action.toast--visible {
  pointer-events: auto;
}

.toast__action {
  margin-left: var(--space-2);
  padding: 0;
  border: none;
  background: none;
  color: var(--color-accent);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

/* ---------------------------------------------------------------------- */
/* Bottom sheet (lightweight modal, e.g. quick note, reason pickers)       */
/* ---------------------------------------------------------------------- */

.sheet-overlay,
.today-sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 210;
  display: flex;
  align-items: flex-end;
  background-color: var(--scrim-sheet);
}

.sheet,
.today-sheet {
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--screen-padding) calc(var(--space-3) + env(safe-area-inset-bottom));
  background-color: var(--color-card);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  box-shadow: var(--shadow-floating);
  animation: sheet-rise var(--motion-sheet) var(--ease-sheet);
  /* If the iOS keyboard shrinks the visible viewport, the sheet's own
     content (reason chips + note + action button) can end up taller than
     what's left on screen. Let the sheet itself scroll rather than push
     Confirm/Done off-screen with no way to reach it. */
  max-height: 85vh;
  max-height: 85dvh;
  overflow-y: auto;
}

/* D1: grabber affordance, drawn (not markup) so every existing sheet gets it
   with no JS change. */
.sheet::before,
.today-sheet::before {
  content: "";
  align-self: center;
  flex: none;
  width: 40px;
  height: 4px;
  margin-top: calc(var(--space-1) * -1);
  border-radius: 2px;
  background-color: var(--color-border);
}

@keyframes sheet-rise {
  from {
    transform: translateY(24px);
    opacity: 0.6;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

/* Today's sheet is rebuilt on every render; only the render that opens it
   animates, so it never flickers while you use it. */
.sheet--static,
.today-sheet.sheet--static {
  animation: none;
}

body.sheet-open {
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .sheet,
  .today-sheet {
    animation: none;
  }
}

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

.sheet__close {
  min-width: 44px;
  min-height: 44px;
  font-size: 22px;
  line-height: 1;
  color: var(--color-text-muted);
  background: none;
  border: none;
  cursor: pointer;
}

.sheet__time {
  color: var(--color-text-muted);
  font-size: 14px;
  margin: 0;
}

/* ---------------------------------------------------------------------- */
/* Rating control (1-5 style selectors, e.g. Movement, Itchiness)          */
/* ---------------------------------------------------------------------- */

.rating-control {
  display: flex;
  gap: var(--space-1);
}

.rating-control__option {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: var(--radius-pill);
  /* White + border rather than the soft surface tint: these controls are
     often nested inside a --color-surface-soft panel (e.g. quick-entry),
     and matching that background made them look flat/non-interactive. */
  background-color: var(--color-card);
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
}

/* Dark text on a light tint + coloured border, not white-on-saturated-fill:
   every category colour (e.g. --category-itchiness at ~1.9:1, --category-
   movement at ~2.4:1) fails WCAG AA badly as a background under white
   text. Text-on-light is safe regardless of which of the 7 hues is used. */
.rating-control__option--selected {
  background-color: var(--color-primary-dark);
  border: 1px solid var(--color-primary-dark);
  color: var(--color-on-primary);
}

/* ---------------------------------------------------------------------- */
/* Score control (1-10 selector, Milestone F11 — Diary)                    */
/* Deliberately its own component rather than a reuse of .rating-control   */
/* above: ten options at a fixed 44px each would overflow a narrow mobile  */
/* viewport (10 * 44px + 9 gaps far exceeds 320-375px), so each option is  */
/* flex:1 (shares the available width evenly) rather than a fixed size.    */
/* Height stays a full 44px (the touch-target dimension that matters most  */
/* for a row of horizontally adjacent buttons) even though width shrinks.  */
/* ---------------------------------------------------------------------- */

.score-control {
  display: flex;
  gap: 3px;
}

.score-control__option {
  flex: 1;
  min-width: 0;
  height: 44px;
  border-radius: var(--radius-small);
  background-color: var(--color-card);
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.score-control__option--selected {
  background-color: var(--color-surface-soft);
  border: 2px solid var(--color-primary-dark);
  color: var(--color-text);
}

.score-control__scale {
  margin: var(--space-0-5) 0 0;
  font-size: 11px;
  color: var(--color-text-muted);
  text-align: center;
}

/* ---------------------------------------------------------------------- */
/* Chip (selectable option, distinct from a read-only status badge)        */
/* ---------------------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background-color: var(--color-card);
  border: 1px solid var(--color-border);
  color: var(--color-text-secondary);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

/* See the rating-control note above: dark text on a light tint + coloured
   border, not white-on-saturated-fill, since every category colour fails
   contrast badly as a white-text background. */
.chip--selected {
  background-color: var(--color-primary-soft);
  border: 1px solid var(--color-primary-dark);
  color: var(--color-primary-dark);
  font-weight: 700;
}

/* Reinforce "selected" with a non-colour cue too, not just the border/fill
   change above. */
.chip--selected::before {
  content: '✓ ';
}

/* Semantic variant for a flag/concern toggle (not a neutral selection) */
.chip--concern.chip--selected {
  background-color: var(--status-warning);
  border-color: var(--status-warning);
  color: var(--color-text);
}
