/* ==========================================================================
   Tracc - Design Tokens (from tokens.json) & Components
   ========================================================================== */

:root {
  /* layout
     The app grows with the screen up to the standard desktop breakpoint
     (1024px) and centres above it. */
  --app-max-width: 1024px;
  --app-gutter: 32px;

  /* Height of the iOS status bar / notch when installed as a PWA with a
     translucent status bar (0 everywhere else). The page draws underneath it,
     so the pinned header adds it to its top padding. */
  --safe-area-top: env(safe-area-inset-top, 0px);

  /* Minimum breathing room between the hero figure and the card's right
     edge. The display type scales down from its default size rather than
     ever coming closer than this. */
  --hero-figure-min-gutter: 32px;

  /* Same clear space on the right of the log sheet's weight figure, measured
     from the edge of the screen. */
  --weight-figure-min-gutter: 32px;

  /* base
     primary is the screen: the page, the header and full-screen sheets.
     secondary is the surface the weight log sheet sits on. */
  --base-background-primary: #182a23;
  --base-background-secondary: #0e1815;
  --base-background-primary-invert: #00482b;
  --base-background-secondary-invert: #d1ffca;
  --base-text-primary: #d1ffca;
  --base-text-secondary: #9fc69b;
  --base-text-oninvert-primary: #0e5127;
  --base-border-primary: #ffffff26;
  --base-border-secondary: #ffffff1a;
  --base-border-oninvert-secondary: #195a40;
  --base-border-oninvert-primary: #4FC858;
  --base-icon-oninvert-primary: #0c2b0b;

  /* button */
  --button-background-primary: #d1ffca;
  --button-background-pressed: #a8d9a1;
  --button-background-hover: #c0f0b9;
  --button-background-secondary: #2B4236;
  --button-background-secondary-hover: #23372C;
  --button-background-secondary-pressed: #203127;
  --button-text-primary: #0c2b0b;
  --button-text-secondary: #31C166;
  --button-icon-oninvert-primary: #00482b;
  --button-icon-primary: #31c166;

  /* control */
  --control-primary: #d1ffca;
  --control-text-primary: #d1ffca;
  --control-text-secondary: #d1ffca;
  --control-text-disabled: #61725e;
  --control-background-pressed: #2c2c2c;
  --control-icon-primary: #31C166;
  --control-icon-secondary: #D1FFCA;
  --control-text-negative: #E94444;

  /* chart
     primary is the current week's bar, secondary the other weeks'. The goal
     colours match the status of the goal, and are neutral until there is
     enough data to judge it. */
  --chart-primary: #d1ffca;
  --chart-secondary: #364840;
  --chart-text-secondary: #7db68a;
  --chart-goal-neutral: #d1ffca80;
  --chart-goal-positive: #31c174;
  --chart-goal-warning: #c18f31;

  /* status: tags that show how a week or a goal is going.
     Neutral until there is enough data to judge; positive is on track,
     warning is off track. */
  --status-background: #203127;
  --status-text: #d1ffca;
  --status-background-positive: #31c174;
  --status-text-positive: var(--base-text-oninvert-primary);
  --status-background-warning: #c18f31;
  --status-text-warning: #45330c;
  /* Shared by every chart mark so positions, lines and fades all move as one.
     Kept in step with CHART_SLIDE_MS in app.js. */
  --chart-travel: 260ms;
  --chart-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* Font families */
  --font-display: 'Unbounded', sans-serif;
  --font-heading: 'Unbounded', sans-serif;
  --font-body: 'Funnel Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  /* Text styles
     Each token is a full `font` shorthand value: weight size/line-height family. */
  --text-display: 500 72px/72px var(--font-display);
  /* Display */
  --text-display-size: 72px;
  /* Display size, overridden by the hero fitter */
  --text-h1: 500 28px/32px var(--font-heading);
  /* H1 */
  --text-h2: 400 20px/28px var(--font-heading);
  /* H2 */
  --text-h3: 500 16px/24px var(--font-heading);
  /* H3 */
  --text-body: 400 16px/24px var(--font-body);
  /* Body */
  --text-body-emphasis: 500 16px/24px var(--font-body);
  /* Body / Emphasis (medium weight 500) */
  --text-caption: 400 14px/20px var(--font-body);
  /* Caption */

  /* Letter-spacing accompanying each text style (not part of `font` shorthand) */
  --text-display-tracking: 0;
  --text-h1-tracking: -0.2px;
  --text-h2-tracking: -0.2px;
  --text-h3-tracking: 0;
  --text-body-tracking: 0;
  --text-body-emphasis-tracking: 0;
  --text-caption-tracking: 0;

  /* Motion */
  --transition-fast: 0.15s ease;
  --transition-base: 0.25s cubic-bezier(0.16, 1, 0.3, 1);

  /* Shadows — shared elevation used by floating/raised components
     (toast, secondary icon buttons, ...) */
  --shadow-elevated: 0 10px 12px 0 #081b0f40,
    0 2px 8px 0 #081b0f26;
  /* Pressed state: the larger shadow's offset presses from 10px down to 5px */
  --shadow-elevated-pressed: 0 5px 12px 0 #081b0f40,
    0 2px 8px 0 #081b0f26;
}

/* Base Reset & Box Sizing */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}

body {
  background-color: var(--base-background-primary);
  color: var(--base-text-primary);
  font: var(--text-body);
  /* The app fills the screen exactly; `dvh` follows the browser chrome */
  height: 100vh;
  height: 100dvh;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 0;
}

/* Header colour behind the status bar. The header already covers it, but a
   fixed strip keeps it in the header colour whatever the page does. */
body:not(.is-empty)::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--safe-area-top);
  background-color: var(--base-background-primary);
  z-index: 19;
}

/* The page itself never scrolls (or rubber-bands). Pulling the weight log
   sheet up compacts the header, and the list scrolls inside the sheet. */
html,
body {
  overflow: hidden;
  overscroll-behavior: none;
}

/* Empty state: there is nothing below the fold to scroll to, so the page
   stays put. The class is set by app.js (and ships in the markup) while
   there are no entries. */
body.is-empty {
  overflow: hidden;
}

/* The list is emptied of groups while there is no data, but it must also
   collapse: an empty sticky header card still renders its gear row, which
   otherwise shows up as a stray bar above the empty state. */
body.is-empty .history-section {
  display: none;
}

/* App Viewport Container
   The app is a single column that grows with the screen: full width on a
   phone, wider on a tablet and up to the desktop breakpoint (1024px), where
   it centres. There is no outer frame, so the header can sit flush
   against the top of the page. */
.app-container {
  width: 100%;
  max-width: var(--app-max-width);
  height: 100%;
  background-color: var(--base-background-primary);
  position: relative;
  display: flex;
  flex-direction: column;
}

/* ==========================================================================
   Home Page Layout
   The hero card sits at the top and the weight log sheet fills the rest of
   the screen beneath it. app.js changes the card's height as the sheet is
   pulled up or down, and the sheet follows its bottom edge.
   ========================================================================== */
.home-page {
  display: flex;
  flex-direction: column;
  width: 100%;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

/* ==========================================================================
   Hero Card (header: figure + chart + goal)
   ========================================================================== */
.hero-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  background-color: var(--base-background-primary);
  /* Flush with the top and sides of the screen (the card also fills the area
     behind the status bar). Its bottom 32px sit behind the weight log sheet,
     whose rounded top corners show the card's colour through. */
  margin: 0;
  border-radius: 0;
  padding: calc(24px + var(--safe-area-top)) 24px 72px;
  overflow: hidden;
  position: relative;
}

/* Compact state: the header's height shrinks as the weight log sheet is pulled
   up. app.js drives this with an inline style:
     height = the card's natural height minus the shrink
   The weight log sheet sits directly beneath the card in the layout, so it
   follows the card's bottom edge.
   - Inner content translates up (`--hero-shift`) and is clipped by the
     header's own box. The top bar (logo and settings) stays where it is: the
     content slides under it, and the chart parks just below it.
   - The goal below the chart is squeezed out once the chart has parked, which
     is what closes the card up to its compact height. */
.hero-card:not(.empty) {
  z-index: 1;
  flex-shrink: 0;
}

/* Inner content scrolls up within the pinned header; children keep their
   natural size while the card's height shrinks around them */
.hero-card:not(.empty)>* {
  flex-shrink: 0;
  will-change: transform;
  transform: translateY(calc(-1 * var(--hero-shift, 0px)));
}

/* The top bar stays put. It has its own background, reaching over the card's
   padding and the status bar, so the rest of the content slides beneath it
   instead of showing through. */
.hero-card:not(.empty)>.hero-topbar {
  position: relative;
  z-index: 3;
  transform: none;
  background-color: var(--base-background-primary);
  margin: calc(-1 * (24px + var(--safe-area-top))) -24px 0;
  padding: calc(24px + var(--safe-area-top)) 24px 0;
  width: calc(100% + 48px);
}

/* Everything between the top bar and the chart (figure, divider), and the goal
   below the chart, fades out as it travels up, rather than being clipped at
   the card's top edge. */
.hero-card:not(.empty)>.hero-info,
.hero-card:not(.empty)>.hero-divider,
.hero-card:not(.empty)>.hero-goal {
  opacity: var(--hero-content-opacity, 1);
}

/* Empty state variant: plain dark header bar with the gear.
   The card starts out in this state (the markup ships with the `empty`
   class) so the accent header never flashes up before the first render. */
.hero-card.empty {
  background-color: transparent;
  margin: 0;
  box-shadow: none;
  border-radius: 0;
  padding: calc(24px + var(--safe-area-top)) 40px 0;
  gap: 0;
}

/* Nothing but the gear shows while there is no data to show */
.hero-card.empty .hero-info,
.hero-card.empty .hero-divider,
.hero-card.empty .hero-chart,
.hero-card.empty .hero-goal {
  display: none !important;
}

.hero-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

/* Logo: the app icon (light shape, header-coloured face) beside the wordmark.
   The icon is built the same way as the splash screen's, in percentages of the
   512px icon grid, so it can play the same wink (the splash-* keyframes are
   defined with the splash styles in index.html). */
.app-logo {
  --wink-duration: 0.7s;
  --face-lag: 0.07s;
  /* Waits for the log sheet to slide away before winking */
  --wink-delay: 0.3s;
  display: flex;
  align-items: center;
  gap: 8px;
}

.app-logo-icon {
  position: relative;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}

.app-logo-shape,
.app-logo-face {
  position: absolute;
  inset: 0;
}

.app-logo-shape {
  border-radius: 21.875%;
  background-color: var(--base-text-primary);
}

.app-logo-icon span {
  position: absolute;
  width: 15.04%;
  border-radius: 999px;
  background-color: var(--base-background-primary-invert);
}

.app-logo-eye-l,
.app-logo-eye-r {
  top: 29.69%;
  height: 33.59%;
}

.app-logo-eye-l { left: 23.63%; }
.app-logo-eye-r { left: 61.33%; }

.app-logo-nose {
  left: 42.58%;
  top: 58.79%;
  height: 15.04%;
}

.app-logo-name {
  font: var(--text-h3);
  letter-spacing: var(--text-h3-tracking);
  color: var(--base-text-primary);
}

/* Added by app.js when a weight is logged */
.app-logo-icon.winking .app-logo-shape {
  animation: splash-tilt var(--wink-duration) cubic-bezier(0.4, 0, 0.2, 1) var(--wink-delay) both;
}

.app-logo-icon.winking .app-logo-face {
  animation: splash-face-tilt var(--wink-duration) cubic-bezier(0.34, 1.7, 0.64, 1)
    calc(var(--wink-delay) + var(--face-lag)) both;
}

.app-logo-icon.winking .app-logo-eye-r {
  animation: splash-wink var(--wink-duration) ease calc(var(--wink-delay) + var(--face-lag)) both;
}

@media (prefers-reduced-motion: reduce) {
  .app-logo-icon.winking .app-logo-shape,
  .app-logo-icon.winking .app-logo-face,
  .app-logo-icon.winking .app-logo-eye-r {
    animation: none;
  }
}

/* Settings Icon Button (gear) */
.settings-btn {
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--transition-fast), opacity var(--transition-fast);
}

.settings-btn:hover {
  transform: rotate(25deg);
  opacity: 0.85;
}

.settings-btn:active {
  transform: rotate(45deg) scale(0.95);
}

.settings-btn .gear-icon {
  width: 24px;
  height: 24px;
  display: block;
}

/* Figure block */
.hero-info {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: flex-start;
  width: 100%;
}

/* The line under the top bar: 24px below it, where the content gap is 40px */
.hero-divider {
  width: 100%;
  height: 1px;
  margin-top: -16px;
  background-color: var(--base-border-secondary);
}

.hero-figure {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  color: var(--base-text-primary);
}

.hero-label {
  font: var(--text-h3);
  letter-spacing: var(--text-h3-tracking);
  color: var(--base-text-primary);
}

.hero-value-wrap {
  display: flex;
  align-items: baseline;
}

.hero-value {
  font: var(--text-display);
  font-size: var(--text-display-size);
  letter-spacing: var(--text-display-tracking);
  color: var(--base-text-primary);
}

.hero-unit {
  font: var(--text-display);
  font-size: var(--text-display-size);
  letter-spacing: var(--text-display-tracking);
  color: var(--base-text-primary);
}

/* Chart inside hero card */
.hero-chart {
  position: relative;
  width: 100%;
  display: flex;
  flex-direction: column;
}

/* ==========================================================================
   Empty State
   ========================================================================== */
.home-empty-state {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex: 1;
  /* The group is centred on the screen, not on the space under the gear row
     (24px above the gear + its 24px height) */
  padding: 0 40px calc(48px + var(--safe-area-top));
  gap: 40px;
}

body.is-empty .app-container {
  padding-bottom: 0;
}

.empty-state-text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.empty-state-title {
  font: var(--text-h2);
  letter-spacing: var(--text-h2-tracking);
  color: var(--base-text-primary);
}

.empty-state-desc {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
  width: 214px;
  max-width: 100%;
}

.empty-state-actions {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
  max-width: 350px;
}

/* ==========================================================================
   Chart
   ========================================================================== */
.chart-wrapper {
  position: relative;
  width: 100%;
  /* 202px in the expanded header; app.js lowers it to 128px as the header
     compacts on scroll */
  height: var(--chart-height, 202px);
}

/* While the chart is being resized by scroll, marks go straight to their new
   spot rather than gliding there */
.chart-wrapper.is-resizing *,
.chart-wrapper.is-resizing *::before {
  transition: none !important;
}

.svg-chart {
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Weekly markers: a rectangle showing the range (min to max) for each week.
   The square showing the average weight is only shown for the currently selected week.
   Purely visual; a transparent hit area on top handles taps and brings the matching week in the
   list beneath the weekly heading */
.chart-box {
  pointer-events: none;
  transition: fill 180ms linear;
}

.chart-range-rect {
  pointer-events: none;
  rx: 8px;
  ry: 8px;
  transition: fill 180ms linear, y var(--chart-travel) var(--chart-ease),
    height var(--chart-travel) var(--chart-ease);
}

.chart-tick line {
  stroke-dasharray: none;
}

/* Value labels use the caption text style; the fill is set per tick from the
   chart colour token in app.js */
.chart-tick text {
  font: var(--text-caption);
  letter-spacing: var(--text-caption-tracking);
  fill: var(--chart-text-secondary);
}

/* Gridlines and their tick labels travel together when the axis range
   shifts, so a value leaving the scale takes its line with it */
.chart-tick {
  transition: transform var(--chart-travel) var(--chart-ease),
    opacity var(--chart-travel) linear;
}

/* Markers glide to their next slot when the list scrolls, so the window
   shift reads as movement rather than a jump. The fade runs the full length
   of the travel rather than finishing early, so a point is already gone by
   the time it reaches the plot edge and never reads as being sliced off. */
.chart-point {
  transition: transform var(--chart-travel) var(--chart-ease),
    opacity var(--chart-travel) linear;
}

/* The goal line: a dotted line across the weeks, where the weekly averages
   should be to meet the goal. Its colour (and its flag's) shows how the goal
   is going: green on track, orange off track, neutral until there is enough
   data to tell. */
.chart-goal {
  --goal-color: var(--chart-goal-neutral);
}

.chart-goal.is-positive,
.chart-goal-marker.is-positive {
  --goal-color: var(--chart-goal-positive);
}

.chart-goal.is-warning,
.chart-goal-marker.is-warning {
  --goal-color: var(--chart-goal-warning);
}

.chart-goal-line {
  fill: none;
  stroke: var(--goal-color);
  stroke-width: 1.5;
  stroke-dasharray: 1 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

/* The goal's flag. A rate goal's flag sits by the line; a target weight's sits
   on the target, with the date it is expected to be reached (when there is
   one) and a short dotted line to mark the weight. It glides with the bars. */
.chart-goal-marker {
  --goal-color: var(--chart-goal-neutral);
  pointer-events: none;
  transition: transform var(--chart-travel) var(--chart-ease),
    opacity var(--chart-travel) linear;
}

.chart-goal-marker[hidden] {
  display: none;
}

.chart-goal-marker .chart-goal-flag {
  fill: none;
  stroke: var(--goal-color);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-goal-marker .chart-goal-target {
  stroke: var(--goal-color);
  stroke-width: 1.5;
  stroke-dasharray: 1 3;
  stroke-linecap: round;
}

.chart-goal-marker .chart-goal-date {
  font: var(--text-caption);
  letter-spacing: var(--text-caption-tracking);
  fill: var(--goal-color);
}

.chart-hit {
  cursor: pointer;
  touch-action: manipulation;
}

.chart-hit:focus {
  outline: none;
}

@media (prefers-reduced-motion: reduce) {

  .chart-point,
  .chart-tick,
  .chart-box,
  .chart-goal-marker,
  .chart-range-rect {
    transition: none;
  }
}

/* ==========================================================================
   Weekly History Lists (flat, divider style)
   ========================================================================== */
/* The weight log bottom sheet. It fills the screen beneath the hero card and
   overlaps the card's last 32px, so its rounded top corners show the card's
   colour. app.js pulls it up by shrinking the card. */
.history-section {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  margin-top: -32px;
  background-color: var(--base-background-secondary);
  border-radius: 20px 20px 0 0;
  overflow: hidden;
}

/* Grab handle: a wide, tall touch target with the small pill drawn inside it.
   Dragging it moves the sheet; tapping it expands or collapses the sheet. */
.sheet-handle {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 2;
  width: 120px;
  height: 36px;
  transform: translateX(-50%);
  background: none;
  border: none;
  cursor: grab;
  touch-action: none;
}

.sheet-handle::before {
  content: '';
  position: absolute;
  top: 16px;
  left: 50%;
  width: 40px;
  height: 4px;
  transform: translateX(-50%);
  border-radius: 999px;
  background-color: var(--base-background-primary);
}

.sheet-handle:focus-visible {
  outline: 2px solid var(--control-primary);
  outline-offset: -4px;
  border-radius: 12px;
}

/* The list scrolls inside the sheet once it is fully up. It starts below the
   handle, and each week's heading sticks to its top edge. */
.history-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  margin-top: 32px;
}

/* Clear space below the list for the home indicator */
.history-scroll::after {
  content: '';
  display: block;
  height: calc(24px + env(safe-area-inset-bottom, 0px));
}

/* The Log weight button is the first thing in the list, so it scrolls away
   as the list moves up */
.sheet-log-action {
  padding: 4px 24px 16px;
}

.sheet-log-action .submit-btn {
  border-radius: 12px;
}

.week-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: 0 8px;
}

.week-group + .week-group {
  margin-top: 16px;
}

/* List heading: week range + average + delta tag. It sticks to the top of the
   list while its week's rows scroll beneath it, and the next week's heading
   takes its place when it arrives. */
.week-header {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  padding: 16px;
  background-color: var(--base-background-secondary);
}

/* With no goal tag, the change sits 4px under the week's name */
.week-header.is-untagged {
  gap: 4px;
}

/* The week's name on the left, its average on the right */
.week-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

/* Below it: the goal tag on the left, the week's change on the one before on
   the right (on its own it sits on the left) */
.week-header-detail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 4px 8px;
}

.week-change {
  font: var(--text-caption);
  letter-spacing: var(--text-caption-tracking);
  color: var(--base-text-secondary);
}

/* A line above each heading but the first, between one week and the next, and
   a line under the heading while it is stuck to the top of the list (app.js
   adds the class). Both run the full width of the sheet. */
.week-header::before,
.week-header::after {
  content: '';
  position: absolute;
  left: -8px;
  right: -8px;
  height: 1px;
  background-color: var(--base-border-secondary);
}

.week-header::before {
  top: 0;
  display: none;
}

.week-group + .week-group .week-header::before {
  display: block;
}

.week-header::after {
  bottom: 0;
  opacity: 0;
  transition: opacity var(--transition-fast);
}

/* Stuck: the line moves from above the heading to below it */
.week-header.is-stuck::before {
  opacity: 0;
}

.week-header.is-stuck::after {
  opacity: 1;
}

.week-range {
  font: var(--text-h3);
  letter-spacing: var(--text-h3-tracking);
  color: var(--base-text-primary);
  white-space: nowrap;
  font-size: var(--week-range-size, 16px);
  line-height: 24px;
  flex-shrink: 1;
  min-width: 0;
}

/* Tag: how a week's change, or a goal, is going. Neutral until there is
   enough data to judge; green when on track, orange when off track. */
.week-delta {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font: var(--text-caption);
  letter-spacing: var(--text-caption-tracking);
  padding: 2px 6px;
  border-radius: 4px;
  background-color: var(--status-background);
  color: var(--status-text);
  white-space: nowrap;
}

.week-delta.is-positive {
  background-color: var(--status-background-positive);
  color: var(--status-text-positive);
}

.week-delta.is-warning {
  background-color: var(--status-background-warning);
  color: var(--status-text-warning);
}

.week-delta svg {
  width: 16px;
  height: 16px;
  display: block;
  flex-shrink: 0;
}

.week-avg {
  display: flex;
  align-items: center;
  gap: 4px;
  font: var(--text-body-emphasis);
  letter-spacing: var(--text-body-emphasis-tracking);
  color: var(--base-text-primary);
  white-space: nowrap;
}

.week-avg strong {
  font: inherit;
  font-weight: inherit;
  color: var(--base-text-primary);
}

/* Daily Entries */
.entries-list {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.list-item,
.entry-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 16px;
  border-radius: 8px;
  cursor: pointer;
  position: relative;
  transition: background-color var(--transition-fast);
  overflow: hidden;
}

.entry-item::after {
  content: '';
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 0;
  height: 1px;
  background-color: var(--base-border-secondary);
  border-radius: 0 0 8px 8px;
}

.entries-list .entry-item:last-child::after {
  display: none;
}

/* Hover only on devices that can hover: touch browsers keep :hover
   applied after a tap, which reads as a stuck pressed state. */
@media (hover: hover) {
  .list-item:hover,
  .entry-item:hover {
    background-color: rgba(255, 255, 255, 0.03);
  }
}

.list-item.is-pressed,
.entry-item.is-pressed {
  background-color: rgba(255, 255, 255, 0.06);
}

.entry-date {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
}

.entry-weight {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-primary);
}

/* ==========================================================================
   Secondary Icon Button (dark surface, light icon + elevation)
   ========================================================================== */
.icon-btn-secondary {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  background-color: var(--button-background-secondary);
  border: none;
  color: var(--button-icon-primary);
  box-shadow: var(--shadow-elevated);
  transition: background-color var(--transition-fast),
    box-shadow var(--transition-fast);
}

.icon-btn-secondary img,
.icon-btn-secondary svg {
  width: 24px;
  height: 24px;
  display: block;
}

.icon-btn-secondary:hover {
  background-color: var(--button-background-secondary-hover);
}

.icon-btn-secondary:active {
  background-color: var(--button-background-secondary-pressed);
  box-shadow: var(--shadow-elevated-pressed);
}

/* ==========================================================================
   Modals & Mobile Sheet Layout (Log Weight & Settings)
   ========================================================================== */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-base);
}

.modal-overlay.active {
  opacity: 1;
  pointer-events: auto;
}

.sheet-dialog {
  position: relative;
  background-color: var(--base-background-primary);
  width: 100%;
  display: flex;
  flex-direction: column;
  /* The sheet is its own scroll context: scrolling it must never chain to the
     page behind, and vertical panning must not fight the gesture handlers. */
  overscroll-behavior: contain;
  touch-action: pan-y;
  transition: transform var(--transition-base);
}

/* The log weight and settings sheets sit on the same surface as the weight log
   sheet. (The goal sheet keeps the screen colour.) */
#logModal .sheet-dialog,
#settingsModal .sheet-dialog {
  background-color: var(--base-background-secondary);
}

/* Mobile: Full Screen Sheet.
   The overlay is sized to the visual viewport by app.js, so the sheet fills
   exactly the part of the screen that is not covered by the keyboard. */
@media (max-width: 639px) {
  .sheet-dialog {
    height: 100%;
    min-height: 100%;
    border-radius: 0;
    transform: translateY(100%);
    /* Respect the notch and home indicator (viewport-fit=cover) */
    padding:
      var(--safe-area-top)
      max(24px, env(safe-area-inset-right))
      max(24px, env(safe-area-inset-bottom))
      max(24px, env(safe-area-inset-left));
  }

  /* A sheet is a screen of its own: the page behind must not scroll or
     rubber-band while it is open. */
  body.modal-open {
    overflow: hidden;
  }

  .modal-overlay.active .sheet-dialog {
    transform: translateY(0);
  }

  /* With the keyboard open the sheet is squeezed into the space above it:
     the number input centres between the header and the date/button
     footer, which sits right above the keyboard. */
  .modal-overlay.keyboard-open .sheet-dialog {
    min-height: 0;
  }

  .modal-overlay.keyboard-open .log-weight-content {
    padding-top: 0;
  }
}

/* Desktop: Centered Modal */
@media (min-width: 640px) {
  .sheet-dialog {
    max-width: 430px;
    border-radius: 20px;
    border: 1px solid var(--base-border-secondary);
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.7);
    transform: scale(0.94) translateY(20px);
    padding: 24px;
    max-height: 90vh;
    overflow-y: auto;
  }

  .modal-overlay.active .sheet-dialog {
    transform: scale(1) translateY(0);
  }
}

/* Modal Top Bar Header (H1 + close icon, bottom border) */
.sheet-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 16px;
  border-bottom: 1px solid var(--base-border-primary);
}

/* The settings screen has just the close button up top; the title sits
   below it as a heading of its own */
.sheet-header-bare {
  justify-content: flex-end;
  padding: 18px 16px;
  border-bottom: none;
}

.settings-title {
  font: var(--text-h1);
  letter-spacing: var(--text-h1-tracking);
  color: var(--base-text-primary);
  padding: 24px 16px;
}

/* Settings sheet content sits 16px from the screen edge (the log sheet keeps
   24px) */
@media (max-width: 639px) {
  #settingsModal .sheet-dialog,
  #goalModal .sheet-dialog {
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
  }

  /* The close icon sits at the same height as the home header's settings cog:
     24px below the safe area. The log sheet's header row is the 28px title
     line with the icon centred in it, so its top padding is 2px less. */
  .sheet-header {
    padding-top: 22px;
  }

  .sheet-header-bare {
    padding-top: 24px;
  }
}

.sheet-title {
  font: var(--text-h2);
  letter-spacing: var(--text-h2-tracking);
  color: var(--base-text-primary);
}

.close-btn {
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity var(--transition-fast), transform var(--transition-fast);
}

.close-btn:hover {
  opacity: 0.8;
  transform: scale(1.1);
}

.close-btn img {
  width: 24px;
  height: 24px;
  display: block;
}

/* Log sheet header actions: optional delete button, then close */
.sheet-header-actions {
  display: flex;
  align-items: center;
  gap: 24px;
}

/* The trash glyph is an <img> rather than a CSS mask: a file:// page is an
   opaque origin, so Chrome blocks mask-image assets and the button would
   paint nothing when index.html is opened directly. delete.svg is drawn in
   control/icon/secondary (#d1ffca). */
.icon-btn-delete {
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  cursor: pointer;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity var(--transition-fast), transform var(--transition-fast);
}

.icon-btn-delete img {
  width: 24px;
  height: 24px;
  display: block;
}

.icon-btn-delete:hover {
  opacity: 0.8;
  transform: scale(1.1);
}

.icon-btn-delete[hidden] {
  display: none;
}

/* ==========================================================================
   Settings Screen & Bottom Sheets
   ========================================================================== */
.settings-screen {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: 100%;
  background-color: var(--base-background-secondary);
}

/* Toggle switch for Enable / Disable */
.toggle-btn {
  position: relative;
  width: 40px;
  height: 24px;
  background-color: var(--base-border-primary);
  border-radius: 12px;
  border: none;
  cursor: pointer;
  transition: background-color var(--transition-fast);
  padding: 0;
}

/* Dimmed while the browser and server are being asked */
.toggle-btn:disabled,
.submit-btn:disabled {
  opacity: 0.6;
  cursor: progress;
}

.toggle-btn[aria-checked="true"] {
  background-color: var(--control-primary);
}

.toggle-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  background-color: var(--base-text-primary);
  border-radius: 50%;
  transition: transform var(--transition-fast), background-color var(--transition-fast);
}

.toggle-btn[aria-checked="true"] .toggle-thumb {
  transform: translateX(16px);
  background-color: var(--base-background-primary);
}

/* Native time picker, invisible and stretched over the whole Time row.
   iOS Safari only opens its picker from a tap that lands on the input itself
   (showPicker() does nothing for a zero-sized input), so the input must be a
   real, tappable target. The 16px font stops iOS zooming the page on focus. */
.notifications-time-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  font-size: 16px;
  cursor: pointer;
}

/* `hidden` must win over the row's display: flex */
.settings-row[hidden] {
  display: none;
}

/* The reminder and its blocked-notifications guidance are bottom sheets that
   rise over the settings screen. The layer dims the screen beneath and takes
   taps outside the sheet; the two sheets swap in place. */
.settings-sheet-layer {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  background-color: rgba(8, 10, 9, 0.75);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--transition-base), visibility 0s linear 0.25s;
  z-index: 5;
}

.settings-sheet-layer.open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity var(--transition-base), visibility 0s;
}

.settings-sheet {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 24px 16px max(24px, env(safe-area-inset-bottom));
  background-color: var(--base-background-secondary);
  border-radius: 24px 24px 0 0;
  transform: translateY(100%);
  visibility: hidden;
  transition: transform var(--transition-base), visibility 0s linear 0.25s;
}

.settings-sheet.active {
  transform: translateY(0);
  visibility: visible;
  transition: transform var(--transition-base), visibility 0s;
}

.settings-sheet-text {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 16px;
}

.settings-sheet-title {
  font: var(--text-h2);
  letter-spacing: var(--text-h2-tracking);
  color: var(--base-text-primary);
}

.settings-sheet-desc {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
}

.submit-btn.settings-sheet-btn {
  width: calc(100% - 32px);
  align-self: center;
}

/* A row that slides open and shut (the reminder time). The grid row animates
   between 0fr and 1fr, which sizes the row to its content without needing a
   fixed height, so the sheet grows and shrinks with it. The transition is only
   switched on (`.animate`, set by app.js) for a change the user makes; opening
   the sheet shows the right state straight away. */
.settings-collapse {
  display: grid;
  grid-template-rows: 0fr;
}

.settings-collapse.open {
  grid-template-rows: 1fr;
}

.settings-collapse-inner {
  min-height: 0;
  overflow: hidden;
  opacity: 0;
}

.settings-collapse.open .settings-collapse-inner {
  opacity: 1;
}

.settings-collapse.animate {
  transition: grid-template-rows var(--transition-base);
}

.settings-collapse.animate .settings-collapse-inner {
  transition: opacity var(--transition-base);
}

@media (prefers-reduced-motion: reduce) {
  .settings-collapse.animate,
  .settings-collapse.animate .settings-collapse-inner {
    transition: none;
  }
}

/* Divider above the first row as well as below each one */
.settings-sheet .settings-content > .settings-row:first-child::before {
  content: '';
  position: absolute;
  left: 16px;
  right: 16px;
  top: 0;
  height: 1px;
  background-color: var(--base-border-secondary);
}

/* In the reminder sheet the last row has no divider below it. That is the
   switch row while the time is hidden, and the time row once it shows, so the
   switch row's divider fades in and out with the time row, and the time row
   never has one. */
.settings-sheet .settings-collapse .settings-row::after {
  display: none;
}

#notificationsToggleRow::after {
  opacity: 0;
}

#notificationsToggleRow.has-divider::after {
  opacity: 1;
}

#notificationsToggleRow.animate::after {
  transition: opacity var(--transition-base);
}

@media (prefers-reduced-motion: reduce) {
  #notificationsToggleRow.animate::after {
    transition: none;
  }
}

/* On desktop the modal is as tall as its content, which would make the sheet
   layer's box depend on the screen showing. One fixed height keeps it stable.
   (Phones are full screen already.) */
@media (min-width: 640px) {
  #goalModal .sheet-dialog {
    height: min(640px, 90vh);
  }

  #settingsModal .sheet-dialog {
    height: min(480px, 90vh);
  }
}

@media (prefers-reduced-motion: reduce) {
  .settings-sheet-layer,
  .settings-sheet {
    transition: none;
  }
}

/* ==========================================================================
   Log Weight Page Elements
   ========================================================================== */
.log-weight-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  flex: 1;
}

/* Big Weight Input Display (Display type, white value + disabled unit) */
.weight-input-container {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  width: 100%;
  flex: 1;
}

.weight-input-wrapper {
  /* Design size for the log figure; app.js lowers this when a long value
     would come too close to the edge of the screen. */
  --weight-input-size: 80px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
  padding: 16px;
}

/* Desktop: the centred modal gives the number input room to breathe, with
   at least 64px of padding above and below the field. The extra spacing
   under the title is dropped so the gaps above and below the input match. */
@media (min-width: 640px) {
  .log-weight-content {
    padding-top: 0;
  }

  .weight-input-wrapper {
    padding-top: 64px;
    padding-bottom: 64px;
  }
}

.weight-number-input {
  background: transparent;
  border: none;
  outline: none;
  color: var(--control-text-secondary);
  font: var(--text-display);
  font-size: var(--weight-input-size);
  line-height: 80px;
  letter-spacing: var(--text-display-tracking);
  width: auto;
  min-width: 0;
  flex: 0 0 auto;
  field-sizing: content;
  text-align: left;
  caret-color: var(--control-text-primary);
}

.weight-number-input::placeholder {
  color: var(--control-text-disabled);
  opacity: 1;
}

/* Hide number spin buttons */
.weight-number-input::-webkit-outer-spin-button,
.weight-number-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.weight-number-input[type=number] {
  -moz-appearance: textfield;
}

.weight-unit-suffix {
  font: var(--text-display);
  font-size: var(--weight-input-size);
  line-height: 80px;
  letter-spacing: var(--text-display-tracking);
  color: var(--control-text-disabled);
}

/* Footer: date row + submit button */
.log-weight-footer {
  display: flex;
  flex-direction: column;
  gap: 24px;
  width: 100%;
}

/* Date Selector Row (list-item style, top border) */
.date-row {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  border-top: 1px solid var(--base-border-primary);
}

.date-label {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-primary);
}

.date-picker-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: none;
  cursor: pointer;
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--control-text-primary);
  padding: 0;
  transition: opacity var(--transition-fast);
}

.date-picker-trigger:hover {
  opacity: 0.8;
}

/* Hidden Native Date Input */
.native-date-input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 0;
  height: 0;
}

/* Submit Action Button (H2 on the accent) */
.submit-btn {
  width: 100%;
  padding: 16px;
  background-color: var(--button-background-primary);
  color: var(--button-text-primary);
  border: none;
  border-radius: 16px;
  font: var(--text-h3);
  letter-spacing: var(--text-h3-tracking);
  cursor: pointer;
  overflow: hidden;
  transition: opacity var(--transition-fast), transform var(--transition-fast),
    background-color var(--transition-fast);
}

/* Secondary variant: dark green fill, light text */
.submit-btn.secondary-btn {
  background-color: var(--button-background-secondary);
  color: var(--base-text-primary);
}

.submit-btn.secondary-btn:hover {
  background-color: var(--button-background-secondary-hover);
  opacity: 1;
}

.submit-btn.secondary-btn:active {
  background-color: var(--button-background-secondary-pressed);
}

.submit-btn:hover {
  opacity: 0.9;
}

.submit-btn:active {
  transform: scale(0.98);
}

/* Loading state: the label gives way to a spinner (the label stays in the
   layout, hidden, so the button keeps its size) and the button is not dimmed
   like a plain disabled one */
.submit-btn {
  position: relative;
}

.btn-spinner {
  display: none;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: btn-spin 0.7s linear infinite;
}

.submit-btn.is-loading,
.submit-btn.is-loading:disabled {
  opacity: 1;
  cursor: progress;
}

.submit-btn.is-loading .btn-label {
  visibility: hidden;
}

.submit-btn.is-loading .btn-spinner {
  display: block;
}

@keyframes btn-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .btn-spinner {
    animation-duration: 1.6s;
  }
}

/* ==========================================================================
   Settings Page Elements (list-item style rows)
   ========================================================================== */
.settings-content {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.settings-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 16px;
  border-radius: 8px;
  cursor: pointer;
  user-select: none;
  position: relative;
  transition: background-color var(--transition-fast);
  overflow: hidden;
}

.settings-row::after {
  content: '';
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 0;
  height: 1px;
  background-color: var(--base-border-secondary);
  border-radius: 0 0 8px 8px;
}

.settings-label {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-primary);
}

.settings-value {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--control-text-primary);
}

/* Hidden File Input for CSV Import */
.csv-file-input {
  display: none;
}

/* ==========================================================================
   Goal (hero header, between the chart and the weight log)
   ========================================================================== */
.hero-goal {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.hero-goal-label {
  font: var(--text-body-emphasis);
  letter-spacing: var(--text-body-emphasis-tracking);
  color: var(--base-text-primary);
}

.hero-goal-label[hidden] {
  display: none;
}

.goal-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  padding: 12px 16px;
  text-align: left;
  font: inherit;
  color: var(--base-text-primary);
  background-color: transparent;
  border: 1px solid var(--base-border-primary);
  border-radius: 12px;
  cursor: pointer;
  transition: background-color var(--transition-fast), scale var(--transition-fast);
}

@media (hover: hover) {
  .goal-card:hover {
    background-color: rgba(255, 255, 255, 0.03);
  }
}

.goal-card:active {
  scale: 0.98;
}

.goal-card-main {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-width: 0;
}

.goal-card-title {
  font: var(--text-body-emphasis);
  letter-spacing: var(--text-body-emphasis-tracking);
  color: var(--base-text-primary);
}

/* The status tag (when there is one) beside a line of text */
.goal-card-detail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
}

.goal-card-text {
  font: var(--text-caption);
  letter-spacing: var(--text-caption-tracking);
  color: var(--base-text-secondary);
}

.goal-card-chevron {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  color: var(--base-text-primary);
}

/* A small clock: the goal needs more data before it can be judged */
.goal-card-hint {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  color: var(--button-icon-oninvert-primary);
}

.goal-card-hint[hidden],
.goal-badge[hidden] {
  display: none;
}

/* ==========================================================================
   Goal Sheet (built from the settings sheet's pieces)
   ========================================================================== */
.goal-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

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

.goal-screen[hidden] {
  display: none;
}

.goal-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 0 16px;
}

.goal-actions {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px 16px 0;
}

.goal-actions .submit-btn[hidden] {
  display: none;
}

/* The screen shown when a goal is complete: a tick, a summary, and what to do
   next, centred in the sheet */
.goal-scroll {
  display: flex;
  flex-direction: column;
}

.goal-screen.goal-complete {
  flex: 1 0 auto;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding: 0 16px 48px;
  text-align: center;
}

.goal-complete-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 80px;
  height: 80px;
  border-radius: 20px;
  background-color: var(--base-background-secondary-invert);
  color: var(--base-background-primary);
}

.goal-complete-icon svg {
  width: 48px;
  height: 48px;
  display: block;
}

.goal-complete-title {
  font: var(--text-h2);
  letter-spacing: var(--text-h2-tracking);
  color: var(--base-text-primary);
}

.goal-complete-summary {
  max-width: 320px;
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
}

.goal-complete-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  margin-top: 8px;
}

.goal-status {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.goal-headline {
  font: var(--text-h2);
  letter-spacing: var(--text-h2-tracking);
  color: var(--base-text-primary);
}

.goal-text,
.goal-note {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
}

.goal-note {
  font: var(--text-caption);
  letter-spacing: var(--text-caption-tracking);
}

.goal-subtitle {
  font: var(--text-h3);
  letter-spacing: var(--text-h3-tracking);
  color: var(--base-text-primary);
  padding-top: 8px;
}

/* Rows that only show a figure: a settings row that isn't tappable */
.goal-body .settings-row {
  padding-left: 0;
  padding-right: 0;
}

.goal-body .settings-row::after {
  left: 0;
  right: 0;
}

.settings-row.is-static {
  cursor: default;
}

.goal-row-sub {
  display: block;
  font: var(--text-caption);
  letter-spacing: var(--text-caption-tracking);
  color: var(--base-text-secondary);
}

/* Form fields */
.goal-field {
  cursor: default;
  gap: 16px;
}

label.goal-field {
  cursor: text;
}

.goal-input-wrap {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.goal-input {
  width: 96px;
  padding: 0;
  text-align: right;
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--control-text-primary);
  background: transparent;
  border: none;
  outline: none;
}

.goal-input::placeholder {
  color: var(--control-text-disabled);
}

.goal-input-unit {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
}

.goal-field[hidden] {
  display: none;
}

.goal-date-controls {
  display: flex;
  align-items: center;
  gap: 16px;
}

.goal-date-clear {
  padding: 0;
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
  background: transparent;
  border: none;
  cursor: pointer;
}

.goal-date-clear[hidden] {
  display: none;
}

.goal-error {
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--control-text-negative);
}

.goal-error[hidden] {
  display: none;
}

/* Two or three options, one selected */
.segmented-control {
  display: flex;
  gap: 4px;
  padding: 4px;
  background-color: var(--button-background-secondary);
  border-radius: 12px;
}

.segmented-option {
  flex: 1;
  padding: 10px 12px;
  font: var(--text-body);
  letter-spacing: var(--text-body-tracking);
  color: var(--base-text-secondary);
  background: transparent;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.segmented-option[aria-pressed="true"] {
  color: var(--button-text-primary);
  background-color: var(--button-background-primary);
}

.segmented-compact {
  flex: none;
}

.segmented-compact .segmented-option {
  flex: none;
  padding: 6px 16px;
}
/* ==========================================================================
   Toast Notification
   ========================================================================== */
/* Drops in from above the viewport, centred over the app */
.toast-container {
  --toast-top: 32px;

  position: fixed;
  top: var(--toast-top);
  left: 0;
  right: 0;
  margin-inline: auto;
  width: fit-content;
  background-color: var(--base-background-secondary-invert);
  color: var(--button-text-primary);
  border-radius: 12px;
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  font: var(--text-body-emphasis);
  letter-spacing: var(--text-body-emphasis-tracking);
  box-shadow: var(--shadow-elevated);
  opacity: 0;
  pointer-events: none;
  transform: translateY(calc(-100% - var(--toast-top)));
  transition: opacity var(--transition-fast), transform var(--transition-base);
  z-index: 200;
  white-space: nowrap;
}

.toast-container.show {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .toast-container {
    transition: none;
  }
}

/* Warnings aren't confirmations, so they go without the tick */
.toast-container.plain .toast-icon {
  display: none;
}

.toast-icon {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
}

.toast-icon img {
  width: 24px;
  height: 24px;
  display: block;
}
