/*
 * The product's own surfaces: the route bar, the month price grid, the alert rows and the console.
 *
 * A file of its own rather than more of 04-components.css, because these are not generic pieces a
 * second product would reuse -- they are this app's one screen. 04 stays the answer to "is there
 * already a component for this"; 07 is the answer to "how does the fare grid work".
 *
 * Sorts after 06-marketing.css, so it can lean on the page frame without fighting it.
 */

/* ------------------------------------------------------------ Route bar ---- */
/* Where the reader says what they are looking at: two selects and the one number that makes the
   whole product's case. Wrapping flex rather than a grid, because the stat card should drop to its
   own line before the two selects squeeze below readable. */
.route-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: stretch; }

/* margin is RESET, not omitted. This is a <label>, and 04-components.css gives every label
   `margin-bottom: 6px` -- correct for a label sitting above an input, wrong for one that IS the
   box. As a stretched flex item the margin comes off the bottom, so the two selects rendered 6px
   shorter than the trip toggle and the price beside them. Same trap as .route-stat being a <p>:
   an element used as a layout box has to say so, and spec/system/layout_boxes_spec.rb walks every
   flex row on the page looking for the next one. */
.route-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin: 0;
  background: var(--field);
  border: 1px solid var(--line2);
  border-radius: var(--r-card);
  padding: 10px 14px;
  min-width: 150px;
  flex: 1 1 150px;
  cursor: pointer;
}
.route-field:focus-within { border-color: var(--accent); }
.route-field__label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  color: var(--text-4);
}
/* appearance:none, then the caret is drawn back on the wrapper. A native select arrow inside a
   bordered card reads as a second, competing border on every platform. */
.route-field select {
  appearance: none;
  background: transparent;
  border: 0;
  outline: none;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 600;
  padding: 0;
  width: 100%;
  cursor: pointer;
}
.route-field select option { background: var(--field); color: var(--text); }

/* Under 420px the two selects stop sharing a row.
   At 360px each field is about 159px wide, and "Ponta Delgada PDL" does not fit in it -- a select
   clips rather than wrapping or ellipsing, so the destination silently read "Ponta Delgada PD".
   Stacking is the honest fix: the label is the thing that must stay readable. */
@media (max-width: 419px) {
  .route-field { flex: 1 1 100%; }
}

/* The headline number. Accent FILL, so it carries --on-accent as its ink.
   margin and max-width are RESET, not omitted: this is a <p>, and 02-base.css gives every
   paragraph `margin: 0 0 1em` and `max-width: var(--measure)`. Both are wrong for a box that is a
   flex item -- the margin eats 1em off the bottom of a stretched item, so the blue card sat
   shorter than the two selects beside it, and the 640px cap stops it growing with them on a wide
   screen. Any <p> used as a layout box has to say so. */
.route-stat {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  margin: 0;
  max-width: none;
  background: var(--accent);
  color: var(--on-accent);
  border-radius: var(--r-card);
  padding: 10px 20px;
  flex: 1 1 190px;
}
.route-stat__label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  opacity: 0.72;
}
.route-stat__value {
  font-family: var(--font-mono);
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.03em;
}
.route-stat__when { font-size: 13px; font-weight: 500; letter-spacing: normal; }

/* One choice with two states, dressed as a route field so the bar stays one row of equal boxes.
   A div with role="radiogroup" rather than a fieldset: see the note in pages/_route_bar for why
   Safari made the <legend> unusable. Being a plain box, it needs none of the fieldset resets. */
.trip-toggle {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 0;
  padding: 9px 14px;
  border: 1px solid var(--line2);
  border-radius: var(--r-card);
  background: var(--field);
  flex: 1 1 190px;
  min-inline-size: 0;
}
/* Just the group's label. It was a <legend> and needed a float to stay inside the box at all;
   as a <span> it is an ordinary flex item and needs nothing. */
.trip-toggle__legend {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  color: var(--text-4);
}
.trip-toggle__options { display: flex; flex-wrap: wrap; gap: 6px; }

.trip-toggle__option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* POSITIONED, so the visually-hidden radio inside is absolute against THIS label rather than
     against whatever positioned ancestor it can find. Without it the input escaped to .page and sat
     at the very top of the document, so clicking the pill focused a control 1,500px away and the
     browser scrolled there: the page appeared to jump to the top on every trip change. */
  position: relative;
  margin: 0;                 /* a <label> again; see .route-field */
  padding: 6px 13px;
  border: 1px solid var(--line3);
  border-radius: var(--r-pill);
  color: var(--text-3);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  /* The same floor .pill and .btn hold. It was ~33px, which is a miss on a phone. */
  min-height: 44px;
  transition: background var(--motion), color var(--motion), border-color var(--motion);
}
.trip-toggle__option:hover { color: var(--text); border-color: var(--accent-70); }
.trip-toggle__option.is-active,
/* PAINTED BY :has(), not only by the server's .is-active. The route bar gets away with the class
   alone because it auto-submits a GET and the page comes back re-rendered with the new one. The
   console's create panel does not submit until "Start watching", so there the class never changes
   and pressing a trip pill would look like nothing happened. Same technique as .pill--check. */
.trip-toggle__option:has(.trip-toggle__input:checked) {
  background: var(--pick);
  color: var(--on-pick);
  border-color: transparent;
}

/* Hidden from sight, NOT from the keyboard or a screen reader: clip rather than display:none, so
   the radio still takes focus and still announces its group. The ring is drawn on the label. */
.trip-toggle__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.trip-toggle__input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: var(--r-pill);
}

/* Under 420px the toggle takes a row of its own rather than squeezing beside a select. */
@media (max-width: 419px) {
  .trip-toggle { flex: 1 1 100%; }
}

/* The console's route row: the same three controls the landing page's .route-bar carries, without
   the price panel beside them. A row rather than a column because that is the axis .route-field and
   .trip-toggle were written for -- see the note in shared/alerts/_route_fields. */
.route-pair { display: flex; flex-wrap: wrap; gap: 10px; }

/* ---------------------------------------------------------- Month strip ---- */
/* Six months, always. A month we hold nothing for keeps its place and shows an em dash -- dropping
   it would shorten the row and quietly change what the reader is comparing.
 
   THE SIX SHARE THE ROW. Sized to their own text they came out 72-75px each and clustered at the
   left of a 1116px container, under a full-width route bar and above a full-width grid -- a short
   ragged row that read as a mistake. `flex: 1 1 0` on the item makes them equal and makes the row
   span its container, and the min-width is what makes the same rule scroll on a narrow screen
   instead of crushing six months into 358px. One rule, both behaviours, no breakpoint. */
.month-strip {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: thin;
  margin: 0;
  /* padding-inline-start, not just padding-bottom. A <ul> carries a 40px start indent from the
     browser, and `list-style: none` does not remove it: the row started 40px right of the grid
     under it, which reads as the first month being nudged in. */
  padding: 0 0 12px;
  list-style: none;
}
/* The <li> is the flex item, not the chip inside it. Putting flex on .month-chip did nothing at
   all, which is half of why the row was ragged. */
.month-strip > li {
  display: flex;
  flex: 1 1 0;
  min-width: 96px;
}

/* The edge fades, drawn only on a side that really has more (scroll_hint_controller.js). A
   permanent fade would be a lie on a desktop, where the row fits. */
.month-strip.has-more-before { mask-image: linear-gradient(to right, transparent, #000 28px); }
.month-strip.has-more-after { mask-image: linear-gradient(to left, transparent, #000 28px); }
.month-strip.has-more-before.has-more-after {
  mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent);
}

.month-chip {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: flex-start;
  justify-content: center;
  width: 100%;
  padding: 10px 16px;
  border-radius: var(--r-card);
  cursor: pointer;
  background: var(--surface);
  border: 1px solid var(--line1);
  color: var(--text-3);
  transition: border-color var(--motion), color var(--motion), background var(--motion);
  min-height: 44px;
}
.month-chip:hover { border-color: var(--line3); color: var(--text); }
.month-chip__label { font-size: 13px; font-weight: 600; letter-spacing: -0.01em; }
.month-chip__price { font-family: var(--font-mono); font-size: 15px; font-weight: 700; }
.month-chip.is-active {
  background: var(--field-hi);
  border-color: var(--accent-70);
  color: var(--text);
}

/* ----------------------------------------------------------- Month grid ---- */
.month-grid {
  background: var(--surface);
  border: 1px solid var(--line1);
  border-radius: var(--r-panel);
  padding: clamp(14px, 2.6vw, 26px);
}
/* CENTRE, NOT BASELINE. The legend on the right is 11px mono and the heading on the left is a
   26px title next to two 38px buttons, so a shared baseline hung the legend off the bottom of a
   much taller block and read as a misalignment -- which it was. */
.month-grid__head {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}
.month-grid__heading { display: flex; align-items: center; gap: 16px; min-width: 0; }

/* TWO SELECTORS DEEP, TO BEAT `.band h2`. That rule gives every heading in a band a 22px bottom
   margin, and it outweighs a bare `.month-grid__title { margin: 0 }` -- so the reset silently did
   nothing and the title kept the margin.

   It looked like a vertical centring bug and was not: a flex row centres MARGIN boxes, so it was
   centring a 51px title against a 38px pair of buttons and putting the arrows 11px low. Measured,
   not guessed. */
.month-grid__head .month-grid__title {
  margin: 0;
  font-size: clamp(20px, 3vw, 26px);
  font-weight: 800;
  letter-spacing: -0.025em;
}

/* The two steps as ONE control, not two loose buttons: a 6px gap holds them together against the
   16px that separates the pair from the title. */
.month-steps { display: flex; align-items: center; gap: 6px; flex: none; }

/* 38px, down from 44. The pair no longer flanks the title, so it does not have to hold its own
   against a 26px heading on both sides -- and 38 still clears the 24px minimum touch target with
   the 6px gap either side of it. */
.month-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: var(--r-pill);
  border: 1px solid var(--accent-24);
  color: var(--accent-text);
  background: var(--accent-08);
  font-size: 16px;
  line-height: 1;
  transition: border-color var(--motion), color var(--motion), background var(--motion);
}
.month-step:hover { border-color: var(--accent-70); background: var(--accent-16); }
/* Kept in place rather than removed at the ends of the range: an arrow that disappears shifts the
   heading under the reader's cursor. It loses the accent as well as the contrast, so "there is
   nothing that way" is legible without reading the colour alone. */
.month-step.is-disabled {
  color: var(--text-5);
  border-color: var(--line1);
  background: transparent;
  cursor: default;
}
.month-grid__legend {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-3);
  margin: 0;
  list-style: none;
  padding: 0;
}
.month-grid__legend li { display: flex; align-items: center; gap: 6px; }
.swatch { width: 10px; height: 10px; border-radius: 3px; display: inline-block; flex: none; }
.swatch--cheap { background: var(--accent); }
.swatch--average { background: var(--accent-24); }
.swatch--high { background: var(--line1); }

/* The grid SCALES rather than scrolls. Seven columns of minmax(0,1fr) with a clamped gap holds its
   shape to 360px; a horizontally scrolling calendar is a calendar you cannot scan, which is the
   one thing this screen exists to let you do. */
.month-grid__days,
.month-grid__week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: clamp(4px, 0.7vw, 8px);
}
.month-grid__days { margin-bottom: 8px; }
.month-grid__day-name {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--text-4);
  text-align: center;
  padding-bottom: 2px;
}
.month-grid__weeks { display: grid; gap: clamp(4px, 0.7vw, 8px); }

.day-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  aspect-ratio: 1 / 0.86;
  border-radius: var(--r-cell);
  padding: 2px;
  border: 1px solid transparent;
  background: transparent;
  font-family: var(--font-sans);
  cursor: pointer;
  transition: transform 120ms ease, border-color var(--motion);
  width: 100%;
}
.day-cell:hover { transform: translateY(-1px); }
.day-cell__date {
  font-family: var(--font-mono);
  font-size: clamp(9px, 1.15vw, 11px);
  line-height: 1;
  opacity: 0.72;
}
.day-cell__price {
  font-family: var(--font-mono);
  font-size: clamp(11px, 1.7vw, 16px);
  font-weight: 700;
  line-height: 1;
}

/* The three tiers, relative to the month on screen. */
.day-cell--cheap { background: var(--accent); color: var(--on-accent); }
.day-cell--average { background: var(--accent-20); color: var(--accent-ink); border-color: var(--line1); }
.day-cell--high { background: var(--line1); color: var(--text-3); border-color: var(--line1); }

/* SAYS "no fare", and is sized so it fits. The cell used to draw an em dash, which reads as "no
   flight" and never meant that. At the price's own size the words run out of a 40px cell on a
   360px screen, so this is smaller and unbolded -- which is right anyway: it is an absence, and
   it should not carry the weight of a number. */
.day-cell__price--none {
  font-size: clamp(8px, 1.15vw, 12px);
  font-weight: 500;
  letter-spacing: -0.01em;
}

/* A day we hold no price for. Dashed and unclickable, so the absence reads as "not offered"
   rather than as "free". */
.day-cell--empty {
  border: 1px dashed var(--line1);
  color: var(--text-5);
  cursor: default;
}
.day-cell--empty:hover { transform: none; }
/* Padding cells exist only to keep the grid rectangular. */
.day-cell--outside { visibility: hidden; }

/* A price the airline has not reconfirmed inside a week. It stays on the grid -- removing it would
   be the quietest kind of lie -- but it is struck through so no one reads it as current. */
.day-cell--stale .day-cell__price { text-decoration: line-through; opacity: 0.7; }

/* The selected day. A NEUTRAL ring, because the selected cell is usually the cheapest one and a
   blue ring on a blue fill reads as nothing at all. */
.day-cell.is-selected {
  border: 2px solid var(--pick-strong);
  box-shadow: 0 0 0 4px var(--pick-22);
}

/* ------------------------------------------------------------ Detail bar --- */
.day-detail {
  margin-top: 18px;
  border-top: 1px solid var(--line1);
  padding-top: 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}
.day-detail__facts { display: flex; flex-wrap: wrap; gap: 6px 22px; align-items: baseline; }
.day-detail__date { font-size: 17px; font-weight: 700; letter-spacing: -0.02em; }
.day-detail__price { font-family: var(--font-mono); font-size: 22px; font-weight: 700; color: var(--accent-text); }
.day-detail__meta { font-size: 13px; color: var(--text-3); }
.day-detail__actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* The watch-this-date control. --pick rather than --accent so it does not compete with the
   cheapest cell sitting directly above it. */
.btn--pick {
  border: 1px solid var(--pick-50);
  background: var(--pick-16);
  color: var(--pick-text);
  font-size: 13px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: var(--r-pill);
}
.btn--pick:hover { background: var(--pick-30); color: var(--pick-text); border-color: var(--pick-50); }

/* ---------------------------------------------------------- Shared bits ---- */
/* The mono uppercase label above a group of controls. The one place the mono face still does what
   it used to do on buttons: mark something as a label rather than as prose. */
.field-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  color: var(--text-4);
  margin: 0 0 9px;
  text-transform: uppercase;
}

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

/* The round control. Filled when chosen, outlined when not. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 14px;
  border-radius: var(--r-pill);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  background: transparent;
  color: var(--text-3);
  border: 1px solid var(--line3);
  transition: background var(--motion), border-color var(--motion), color var(--motion);
  min-height: 44px;
}
.pill:hover { color: var(--text); border-color: var(--accent); }
.pill.is-active {
  background: var(--pick);
  color: var(--on-pick);
  border-color: transparent;
}

/* A pill wrapping a real checkbox or radio. The input is the accessible control and the pill is
   its label -- so :has() paints the state rather than a class the server has to keep in step. */
.pill--check input { position: absolute; opacity: 0; width: 0; height: 0; }
.pill--check:has(input:checked) {
  background: var(--accent);
  color: var(--on-accent);
  border-color: transparent;
}
.pill--check:has(input:focus-visible) { outline: 2px solid var(--accent-text); outline-offset: 2px; }

/* A blocker sentence is a sentence, not a label: "SMS - verify your number" is about 200px at 13px
   and .pill forbids it wrapping, so it pushed the row sideways instead of breaking. */
.pill--disabled { white-space: normal; max-width: 100%; }

/* A channel that cannot reach anyone yet. Offered rather than hidden: it says the product can do
   this and what is missing. */
.pill--disabled {
  color: var(--text-4);
  border-style: dashed;
  cursor: default;
  font-weight: 500;
}
.pill--disabled:hover { color: var(--text-4); border-color: var(--line3); }
a.pill--disabled { cursor: pointer; }
a.pill--disabled:hover { color: var(--accent-text); border-color: var(--accent); }

.field-input {
  flex: 1 1 180px;
  background: var(--field);
  border: 1px solid var(--line2);
  border-radius: var(--r-input);
  padding: 13px 15px;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  outline: none;
  min-height: 44px;
}
.field-input:focus { border-color: var(--accent); }

/* --------------------------------------------------------- Trigger form --- */
.trigger { display: flex; flex-direction: column; gap: 16px; }
.trigger__note { margin: 0; font-size: 13px; line-height: 1.55; color: var(--text-3); }

.threshold { display: flex; flex-direction: column; gap: 8px; }
.threshold__head { display: flex; justify-content: space-between; align-items: baseline; }
.threshold__label { font-size: 14px; color: var(--text-2); }
.threshold__value { font-family: var(--font-mono); font-size: 24px; font-weight: 700; color: var(--accent-text); }
/* The 4px was the TRACK, but on the element it is also the HIT AREA, and a 4px-tall control cannot
   be grabbed with a thumb. Dropping the height gives the engine its own track back and min-height
   makes the box catchable; every engine centres the track inside it. accent-color still paints it,
   which appearance: none would forfeit. */
.threshold input[type="range"] { width: 100%; min-height: 44px; accent-color: var(--accent); }
.threshold__bounds {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-4);
  margin: 0;
}

.date-pair { display: flex; gap: 10px; flex-wrap: wrap; }
.date-field {
  flex: 1 1 130px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  background: var(--field);
  border: 1px solid var(--line2);
  border-radius: var(--r-input);
  padding: 9px 12px;
}
.date-field .field-label { margin: 0; }
/* `color-scheme: light` on :root is what pins the native picker to the page. Without it a
   dark-preferring OS opens a dark date picker on this light page. */
.date-field input {
  background: transparent;
  border: 0;
  outline: none;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  width: 100%;
  min-height: 28px;
}

.delivery { display: flex; flex-direction: column; gap: 16px; }

/* ------------------------------------------------------------ Alert rows --- */
.alert-row {
  background: var(--surface);
  border: 1px solid var(--line1);
  border-radius: var(--r-row);
  overflow: hidden;
  transition: border-color var(--motion);
}
.alert-row[open] { border-color: var(--pick-50); }
.alert-row--paused { opacity: 0.72; }

.alert-row__head {
  list-style: none;
  cursor: pointer;
  padding: clamp(14px, 2.2vw, 20px);
  display: flex;
  flex-wrap: wrap;
  gap: 12px 18px;
  align-items: center;
  justify-content: space-between;
}
/* Safari draws its own disclosure triangle through ::-webkit-details-marker, which list-style
   alone does not remove. */
.alert-row__head::-webkit-details-marker { display: none; }
.alert-row__head::before {
  content: "▸";
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-4);
  flex: none;
}
.alert-row[open] .alert-row__head::before { content: "▾"; }

.alert-row__identity { display: flex; flex-direction: column; gap: 4px; min-width: 0; margin-right: auto; }
.alert-row__route { font-size: 17px; font-weight: 700; letter-spacing: -0.02em; }
.alert-row__rule { font-size: 13px; color: var(--text-3); }

.alert-row__status { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.alert-row__figures { display: flex; flex-direction: column; gap: 3px; text-align: right; }
.alert-row__floor { font-family: var(--font-mono); font-size: 17px; font-weight: 700; color: var(--accent-text); }
.alert-row__hits { font-size: 11px; color: var(--text-4); }

.status-pill {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  padding: 4px 9px;
  border-radius: var(--r-pill);
  background: var(--line1);
  color: var(--text-4);
}
.status-pill--on { background: var(--accent-18); color: var(--accent-text); }

.alert-row__body { border-top: 1px solid var(--line1); padding: clamp(14px, 2.2vw, 22px); }
/* WHEN and HOW, side by side under the route row. The margin is what separates it from that row;
   the two are siblings in one form rather than a third column, because the route is the fact the
   other two are about and reads first at every width. */
.alert-row__form {
  margin-top: 18px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 22px;
  align-items: start;
}
.alert-row__col { display: flex; flex-direction: column; gap: 16px; }
.alert-row__actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 18px; align-items: end; }
.alert-row__actions form { margin: 0; }

/* The create panel. A row with nothing behind it yet, so it borrows the row's box and says the one
   thing that is different about it: this is the way in, not one of the things already running. */
.alert-row--new { border-style: dashed; }
.alert-row--new[open] { border-style: solid; }
.alert-row--new .alert-row__route { color: var(--accent-text); }

/* ------------------------------------------- Alert rows, narrow ----------- */
/* The head is four blocks on one line, and it stops fitting well before a phone: at ~620px the
   route heading is squeezed under 80px and "Ponta Delgada" wraps to four lines beside a status
   block with room to spare. So it stacks here rather than at the 420px the selects use. */
@media (max-width: 619px) {
  /* Only the STATUS takes a full line. Widening the identity to 100% too would push the disclosure
     marker -- which is a flex item, being a ::before on the row of items -- onto a line of its own
     above the heading, where it reads as a stray character rather than as a control. */
  .alert-row__status { flex: 1 1 100%; justify-content: space-between; gap: 8px 12px; }
  /* Right-aligned text flush against the LEFT edge is what `text-align: right` becomes once the
     figures have a row to themselves. On its own line the pair reads as a row. */
  .alert-row__figures { flex-direction: row; align-items: baseline; gap: 8px; text-align: left; }
  .alert-row__actions .btn { flex: 1 1 auto; justify-content: center; }
}

@media (max-width: 419px) {
  /* A date input is as wide as its formatted date plus the native picker glyph, which is more than
     130px on Chrome. Two of them side by side clipped the year. */
  .date-field { flex: 1 1 100%; }
  .threshold__head { flex-wrap: wrap; gap: 2px 12px; }
  .threshold__value { font-size: 20px; }
  .threshold__bounds { font-size: 9px; gap: 6px; }
}

/* ---------------------------------------------------------- Hero + bands --- */
.hero__title {
  font-size: clamp(38px, 7.4vw, 76px);
  line-height: 0.94;
  letter-spacing: -0.035em;
  font-weight: 800;
  margin: 0 0 20px;
  max-width: 15ch;
  text-wrap: balance;
}
.hero__lede {
  font-size: clamp(16px, 2.2vw, 20px);
  line-height: 1.5;
  color: var(--text-3);
  max-width: 52ch;
  margin: 0 0 32px;
}

/* The honest empty state. A month with no fares says so in a sentence, rather than showing an
   empty grid that reads as a bug. */
.empty-note { margin: 16px 0 0; font-size: 15px; line-height: 1.6; color: var(--text-3); max-width: 60ch; }

/* ------------------------------------------------------- Subscribe band ---- */
/* auto-fit minmax is what makes this one column at 360px and two on a laptop with no breakpoint of
   its own. */
.alerts-band {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: clamp(24px, 4vw, 48px);
  align-items: start;
}
.alerts-band__copy { min-width: 0; }
.alerts-band__title {
  font-size: clamp(28px, 4.6vw, 44px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  font-weight: 800;
  margin: 0 0 16px;
  max-width: 16ch;
}
.alerts-band__lede { font-size: 16px; line-height: 1.6; color: var(--text-3); max-width: 44ch; margin: 0 0 22px; }

.dotted-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.dotted-list li {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  font-size: 14px;
  color: var(--text-2);
  line-height: 1.5;
}
.dotted-list li::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  margin-top: 7px;
  flex: none;
}

.subscribe-card {
  background: var(--surface);
  border: 1px solid var(--line2);
  border-radius: var(--r-panel);
  padding: clamp(18px, 3vw, 28px);
}
.subscribe-form { display: flex; flex-direction: column; gap: 18px; }
.subscribe-form__submit { display: flex; gap: 8px; flex-wrap: wrap; }

/* THE WHOLE RULE, IN ONE SENTENCE, where four pills and a slider used to be. It carries the card
   now, so it is set at reading size rather than as a caption -- this is the thing a reader has to
   understand before they type an address, and it is the only thing. */
.subscribe-card__promise {
  margin: 0;
  max-width: 34ch;
  font-size: clamp(19px, 2.2vw, 23px);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--text);
  text-wrap: balance;
}
.subscribe-form__summary { margin: 0; font-size: 12px; color: var(--text-4); line-height: 1.5; }

/* The price, stated where the commitment is made. Ruled off above rather than boxed: it belongs to
   the button below it, not to the controls above. */
.subscribe-price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 0;
  padding-top: 16px;
  border-top: 1px solid var(--line1);
  font-size: 14px;
  line-height: 1.5;
}
.subscribe-price__amount { font-family: var(--font-mono); font-weight: 700; color: var(--text); }
.subscribe-price__note { color: var(--text-3); }
.subscribe-price__link { margin-left: auto; font-size: 13px; font-weight: 600; white-space: nowrap; }

/* -------------------------------------------------------- Console band ----- */
/* The signed-in console. --sunk rather than --bg, so the band reads as a floor the alerts sit on
   rather than as one more section of the marketing page above it. */
.console-band {
  background: var(--sunk);
  border-top: 1px solid var(--line1);
}
/* .page-inner supplies the horizontal gutter; this adds only the vertical rhythm, because the band
   is rendered outside the container and cannot inherit .band's padding. */
.console-band__inner { padding-block: clamp(36px, 6vw, 72px); }
.console-band__head {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 26px;
}
.console-band__account { margin: 0; font-size: 15px; color: var(--text-3); }
.console-band__actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.alert-stack { display: flex; flex-direction: column; gap: 12px; }

/* ------------------------------------------------------------ Console page -- */
.tab-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 24px; }
.tab-row .pill.is-active { background: var(--field-hi); color: var(--text); border-color: var(--pick-50); }

.account-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  align-items: start;
}
.account-column { display: flex; flex-direction: column; gap: 12px; }

.account-card {
  background: var(--surface);
  border: 1px solid var(--line1);
  border-radius: var(--r-row);
  padding: clamp(16px, 2.4vw, 24px);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.account-card__head {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
}
.account-card__title { margin: 0; font-size: 18px; font-weight: 800; letter-spacing: -0.02em; }
.account-card__renewal { margin: 0; font-family: var(--font-mono); font-size: 12px; color: var(--text-3); }
.account-card__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.account-card__actions form { margin: 0; }

/* 150px, not 180: the console's account column is about 340px wide inside its padding, and at
   180 the two plan cards wrapped to one column on every laptop rather than only on a phone. */
.plan-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.plan-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  text-align: left;
  padding: 18px;
  border-radius: var(--r-card);
  cursor: pointer;
  background: var(--plan-idle);
  border: 1px solid var(--line2);
  color: var(--text);
  width: 100%;
  font-family: var(--font-sans);
}
.plan-card--current { background: var(--plan-on); border-color: var(--accent-70); cursor: default; }
.plan-card__badge {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  padding: 4px 9px;
  border-radius: var(--r-pill);
  background: var(--line1);
  color: var(--text-3);
}
.plan-card--current .plan-card__badge { background: var(--accent); color: var(--on-accent); }
.plan-card__price { font-family: var(--font-mono); font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
.plan-card__line { font-size: 13px; color: var(--text-3); line-height: 1.45; }
.plan-cards form { margin: 0; display: contents; }

.invoice-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.invoice {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid var(--line1);
  padding-top: 10px;
  margin-top: 10px;
}
.invoice__what { display: flex; flex-direction: column; gap: 2px; }
.invoice__date { font-size: 14px; font-weight: 600; }
.invoice__label { font-size: 12px; color: var(--text-4); }
.invoice__how-much { display: flex; align-items: center; gap: 14px; }
.invoice__amount { font-family: var(--font-mono); font-size: 14px; }
.invoice__receipt { font-size: 12.5px; font-weight: 600; }

.settings-form { display: flex; flex-direction: column; gap: 12px; }
.field-select {
  background: transparent;
  border: 0;
  outline: none;
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 600;
  width: 100%;
  min-height: 28px;
}

.switch-row { display: flex; gap: 14px; align-items: center; justify-content: space-between; }
.switch-row__label { font-size: 14px; color: var(--text-2); line-height: 1.45; }

/* A real checkbox under a painted track. :has() paints the state, so the input stays the
   accessible control rather than being reimplemented by a div with a click handler. */
.switch { position: relative; flex: none; cursor: pointer; display: inline-flex; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch__track {
  width: 46px;
  height: 26px;
  border-radius: var(--r-pill);
  background: var(--line3);
  display: block;
  transition: background var(--motion);
}
.switch__knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--text);
  transition: left 160ms ease;
}
.switch:has(input:checked) .switch__track { background: var(--accent); }
.switch:has(input:checked) .switch__knob { left: 23px; }
.switch:has(input:focus-visible) .switch__track { outline: 2px solid var(--accent-text); outline-offset: 2px; }

.channel-setup {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  border-top: 1px solid var(--line1);
  padding-top: 14px;
}
.channel-setup form { margin: 0; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.channel-setup__form { flex: 1 1 100%; }
.channel-setup__state { margin: 0; font-size: 13px; color: var(--text-3); flex: 1 1 100%; }

/* The conversion note, under every surface that shows a fare.
   Small and quiet: it is a qualifier on the prices above it, not a warning. It sits at the bottom of
   the block it qualifies, in the mono face the rest of the numeric furniture uses. */
.conversion-note {
  margin: 12px 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-3);
  max-inline-size: 70ch;
}

/* The airline's own fare, beside our converted one in the detail bar. Quieter than the euro figure:
   it is the number a reader checks against, not the number they scan. */
.day-detail__usd {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-3);
}
