/* Dark, but not a terminal.
 *
 * **This app diverges from congo and tracker on purpose, and here is the
 * whole of it.** Those two are read by the person who built them: monospace
 * everywhere, no capitalisation anywhere, every value the same size because
 * the reader already knows what each one is. This one has a second reader, and
 * the complaint that produced this file was "all the data just blurs together
 * -- take Irie's, it's kinda hard to know what is what".
 *
 * So three things changed and nothing else did:
 *
 *   1. **A sans-serif face for words**, with monospace kept only where digits
 *      have to line up -- a schedule's times, a phone number. Monospace prose
 *      was costing legibility and buying nothing.
 *   2. **Real capitals.** "Irie's Island Food" reads as a restaurant; the
 *      lowercase version reads as a filename.
 *   3. **A type hierarchy that encodes what a thing is.** A name is large and
 *      bright, a field label is small and quiet and uppercase, a value sits
 *      beside its label. That pairing is the actual fix: nothing blurs when
 *      every value has a name next to it.
 *
 * The ground is unchanged from tracker, deliberately -- it is still one of
 * Chad's apps and should still look like one.
 */

:root {
  color-scheme: dark;

  /* Ground and surfaces. The card is lifted off the page rather than ruled
     off it: twenty-four hairlines in a column read as a table, and this is a
     list of things, not a table of them. */
  --bg:        #0B0E14;
  --surface:   #161B24;
  --surface-2: #1C2230;
  --line:      #2A3442;

  /* Text, in three ranks that mean three different things. The gap between
     --ink and --muted is what carries the hierarchy now that everything is
     not the same size. */
  --ink:       #E2E8F0;   /* a name, a value: the thing you are reading */
  --muted:     #9AA4B2;   /* a description, a note */
  --faint:     #767F8D;   /* a field label, a missing value, a timestamp */

  --link:      #79C0FF;
  --good:      #7EE787;
  --warn:      #D9A441;
  --bad:       #E08894;

  /* Instrument Sans for words, JetBrains Mono for digits. Both from Google,
     both with a real fallback stack behind them -- this app runs on a laptop
     that is sometimes on a ferry, and a silent fallback to a system sans is a
     perfectly good outcome. */
  --sans: "Instrument Sans", ui-sans-serif, system-ui, -apple-system,
          "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
          "Liberation Mono", monospace;

  --measure: 56rem;
  --tap: 1.9rem;
  --radius: 8px;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html { background: var(--bg); }

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

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; border-radius: 3px; }

::selection { background: color-mix(in srgb, var(--link) 30%, var(--bg)); color: #fff; }

main {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 2rem 1.25rem 6rem;
}

/* One type scale, used everywhere. */
h1 { font-size: 1.6rem; font-weight: 600; letter-spacing: -0.015em; margin: 0 0 0.25rem; }
h2 { font-size: 1.05rem; font-weight: 600; margin: 2rem 0 0.75rem; }
h3 { font-size: 1.1rem; font-weight: 600; letter-spacing: -0.01em; margin: 0; }

/* The quiet uppercase label, which is the same object everywhere it appears:
   a field name, a section eyebrow, a nav heading. Letter-spaced because small
   uppercase without it sets too tight to read. */
.eyebrow,
.facts dt,
.card-rail dt {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--faint);
}

/* --- header ------------------------------------------------------------- */

header.site {
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 5;
}

.bar {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0.7rem 1.25rem;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.wordmark { color: var(--ink); font-weight: 600; letter-spacing: -0.01em; }
.wordmark:hover { text-decoration: none; color: var(--link); }
.bar .sep { color: var(--faint); }
.bar .where { color: var(--muted); }

.flash {
  margin: 0 0 1.5rem;
  padding: 0.65rem 0.85rem;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--good) 12%, var(--bg));
  border: 1px solid color-mix(in srgb, var(--good) 35%, transparent);
}
.flash.is-alert {
  background: color-mix(in srgb, var(--warn) 12%, var(--bg));
  border-color: color-mix(in srgb, var(--warn) 35%, transparent);
}

.nothing { color: var(--muted); }
code { font-family: var(--mono); font-size: 0.88em; color: var(--link); }

/* --- the list of trips --------------------------------------------------- */

.trip-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.15rem 1rem;
  padding: 0.9rem 1rem;
  margin-bottom: 0.6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}
.trip-row:hover { background: var(--surface-2); text-decoration: none; border-color: var(--faint); }

.trip-name { font-size: 1.1rem; font-weight: 600; }
.trip-when { grid-column: 1; color: var(--muted); font-size: 0.9rem; }
.trip-nights { grid-row: 2; grid-column: 2; color: var(--faint); font-size: 0.85rem; }
.trip-until {
  grid-row: 1; grid-column: 2;
  color: var(--good); font-size: 0.8rem; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.dash { padding: 0 0.3em; color: var(--faint); }

/* --- a trip -------------------------------------------------------------- */

.trip-head { margin-bottom: 1.25rem; }
.trip-facts {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.6rem;
  color: var(--muted);
  font-size: 0.95rem;
}
.trip-facts .fact:not(:last-child)::after { content: "·"; color: var(--faint); padding-left: 0.6rem; }
.trip-facts .is-soon { color: var(--good); font-weight: 600; }

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
}

/* Label-and-value rows. The single most important rule in this file: a fixed
   label column in a quiet uppercase, the value beside it in body text. This
   is what stops a card reading as one grey paragraph. */
.facts {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 0.45rem 1rem;
  margin: 0;
}
.facts dt { padding-top: 0.18rem; }
.facts dd { margin: 0; }
.facts .num { font-family: var(--mono); font-size: 0.88em; font-variant-numeric: tabular-nums; }

/* "No hours found". Italic and quiet, so it reads as a checked absence rather
   than as content. */
.missing { color: var(--faint); font-style: italic; }

.places-link { margin: 1.5rem 0 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.75rem; }
.places-shut { color: var(--warn); font-size: 0.9rem; }

/* --- the schedule -------------------------------------------------------- */

.day { margin: 0 0 1.25rem; }

.day h3 {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.75rem;
  padding: 0 0 0.5rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 0.5rem;
}
.day-name { font-size: 1.05rem; }
.day-mark {
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--good);
  padding: 0.1rem 0.45rem;
  border-radius: 100px;
  background: color-mix(in srgb, var(--good) 14%, transparent);
}
.day.is-empty .day-mark { color: var(--faint); background: color-mix(in srgb, var(--faint) 14%, transparent); }
.day-sun { margin-left: auto; color: var(--faint); font-size: 0.85rem; font-weight: 400; }

.open-day { margin: 0; padding: 0.6rem 0; color: var(--faint); font-style: italic; }

.events { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.25rem; }

.event {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: 0 1rem;
  padding: 0.65rem 0.8rem;
  border-radius: 6px;
  background: var(--surface);
  border-left: 3px solid var(--line);
}

/* The left rail: when, and what sort of thing. It used to hold only the time,
   spanned down beside a four-row body, which left a tall empty column next to
   the longest events. */
.event-when { display: flex; flex-direction: column; gap: 0.1rem; }

/* Times stay monospace and tabular -- this is the one place in the app where
   digits form a column and the alignment is the whole point. */
.event-time {
  font-family: var(--mono);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.event-kind {
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.07em;
  text-transform: uppercase;
}
.event-span { color: var(--faint); font-family: var(--mono); font-size: 0.76rem; }

.event-body { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.event-title { font-weight: 500; }

/* The place reads as a location rather than as a second title. */
.event-place { color: var(--muted); font-size: 0.9rem; }
.event-place::before { content: "↳ "; color: var(--faint); }

/* **The note is detail, and is set like detail.** Held to a readable measure
   rather than the full width of the row, with air above it, so a long one
   reads as a paragraph belonging to the event instead of as the event itself.
   Everything above it stays on one line each, which is what makes the card
   scannable with the note still on it. */
.event-notes {
  margin: 0.35rem 0 0;
  max-width: 58ch;
  color: var(--faint);
  font-size: 0.9rem;
  line-height: 1.5;
}

.event[data-kind="drive"]   { border-left-color: var(--faint); }
.event[data-kind="drive"]   .event-kind { color: var(--faint); }
.event[data-kind="lodging"] { border-left-color: var(--good); }
.event[data-kind="lodging"] .event-kind { color: var(--good); }
.event[data-kind="eat"]     { border-left-color: var(--warn); }
.event[data-kind="eat"]     .event-kind { color: var(--warn); }
.event[data-kind="drink"]   { border-left-color: #7FCACA; }
.event[data-kind="drink"]   .event-kind { color: #7FCACA; }
.event[data-kind="do"]      { border-left-color: var(--link); }
.event[data-kind="do"]      .event-kind { color: var(--link); }
.event[data-kind="shop"]    { border-left-color: #B48EAD; }
.event[data-kind="shop"]    .event-kind { color: #B48EAD; }
.event[data-kind="note"]    .event-kind { color: var(--faint); }

.trip-notes p { color: var(--muted); max-width: 66ch; }

/* --- filters ------------------------------------------------------------- */

.filters {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
  margin: 1.25rem 0 0;
}
.filters a, .filters .is-empty {
  font-size: 0.85rem;
  padding: 0.3rem 0.7rem;
  border-radius: 100px;
  border: 1px solid var(--line);
  color: var(--muted);
}
.filters a:hover { text-decoration: none; border-color: var(--faint); color: var(--ink); }
.filters a.is-here {
  background: color-mix(in srgb, var(--good) 16%, transparent);
  border-color: color-mix(in srgb, var(--good) 45%, transparent);
  color: var(--good);
  font-weight: 600;
}
.filters .count { color: var(--faint); font-variant-numeric: tabular-nums; }
.filters a.is-here .count { color: inherit; }
.filters .is-empty { color: var(--faint); opacity: 0.6; cursor: default; }
.filters.is-verdicts { margin-top: 0.5rem; }

/* --- a place card -------------------------------------------------------- */

.places { display: flex; flex-direction: column; gap: 0.75rem; }

.place {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem 0;
}

.card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.85rem; }
.place-name { font-size: 1.15rem; }
.place-name a { color: var(--ink); }
.place-name a:hover { color: var(--link); }
.place-about { margin: 0.15rem 0 0; color: var(--muted); font-size: 0.93rem; }

/* How well a vegetarian eats here, said in words and given a pill of its own.
   A sequential ramp, not four unrelated hues: this is one scale with a
   direction. `Not checked` is deliberately the quietest -- it is an admission,
   not a verdict, and should not compete with a real answer. */
.place-veg {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 0.22rem 0.55rem;
  border-radius: 100px;
  white-space: nowrap;
}
.place-veg::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.place[data-veg="good"]    .place-veg { color: var(--good); background: color-mix(in srgb, var(--good) 15%, transparent); }
.place[data-veg="some"]    .place-veg { color: #7FCACA; background: color-mix(in srgb, #7FCACA 15%, transparent); }
.place[data-veg="thin"]    .place-veg { color: var(--warn); background: color-mix(in srgb, var(--warn) 15%, transparent); }
.place[data-veg="unknown"] .place-veg { color: var(--faint); background: color-mix(in srgb, var(--faint) 15%, transparent); }

/* The thing you are actually scanning for, lifted out of the pile. It was the
   third grey paragraph down; now it has a surface. */
.place-eat {
  margin: 0.85rem 0 0;
  padding: 0.6rem 0.75rem;
  border-radius: 6px;
  border-left: 3px solid var(--good);
  background: color-mix(in srgb, var(--good) 9%, transparent);
}
.place-eat dt { color: var(--good); margin-bottom: 0.1rem; }
.place-eat dd { margin: 0; font-size: 0.95rem; }

/* A closure that lands on a day of this trip. Amber, because it is a
   constraint to plan around rather than a mistake -- the place is fine, it is
   just shut. */
.place-shut {
  display: flex;
  gap: 0.5rem;
  margin: 0.85rem 0 0;
  padding: 0.5rem 0.7rem;
  border-radius: 6px;
  font-size: 0.92rem;
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
}

.place .facts { margin: 0.85rem 0 0; }
.place-notes { color: var(--muted); font-size: 0.93rem; }
.place-checked { color: var(--faint); font-size: 0.82rem; }

.place-links { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.95rem 0 0; }
.btn {
  display: inline-block;
  font-size: 0.85rem;
  font-weight: 500;
  padding: 0.3rem 0.75rem;
  border-radius: 100px;
  border: 1px solid color-mix(in srgb, var(--link) 50%, transparent);
  color: var(--link);
}
.btn:hover { text-decoration: none; background: color-mix(in srgb, var(--link) 14%, transparent); }
/* A link that does not exist, drawn rather than omitted -- see `or_missing`. */
.btn-off {
  border-color: var(--line);
  color: var(--faint);
  font-style: italic;
  cursor: default;
}

/* --- voting -------------------------------------------------------------- */

.vote {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.25rem;
  margin: 1rem -1.1rem 0;
  padding: 0.65rem 1.1rem;
  border-top: 1px solid var(--line);
}
.vote form { display: inline; margin: 0; }
.vote-who { display: inline-flex; align-items: center; gap: 0.35rem; }
.vote-name { font-size: 0.85rem; font-weight: 600; color: var(--muted); margin-right: 0.15rem; }

.vote-key {
  font: inherit;
  font-size: 0.95rem;
  line-height: 1;
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0 0.5rem;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: transparent;
  cursor: pointer;
  /* Unvoted thumbs are desaturated so a cast one is obvious at a glance --
     the fill and the border agree with it, so colour is never the only cue. */
  filter: grayscale(1) opacity(0.5);
}
.vote-key:hover { filter: none; border-color: var(--faint); }
.vote-key.is-cast { filter: none; }
.vote-key.is-yes.is-cast { background: color-mix(in srgb, var(--good) 22%, transparent); border-color: var(--good); }
.vote-key.is-no.is-cast  { background: color-mix(in srgb, var(--bad) 22%, transparent);  border-color: var(--bad); }

.vote-agreement {
  margin-left: auto;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--faint);
}
.vote[data-agreement="both_up"] .vote-agreement { color: var(--good); }
.vote[data-agreement="both_down"] .vote-agreement { color: var(--bad); }
.vote[data-agreement="split"] .vote-agreement { color: var(--warn); }

/* A place you have both said yes to is decided, and should be findable by
   scrolling rather than by reading. One they have both rejected recedes. */
.place:has(.vote[data-agreement="both_up"]) { border-color: color-mix(in srgb, var(--good) 45%, transparent); }
.place:has(.vote[data-agreement="both_down"]) { opacity: 0.6; }

/* --- narrow -------------------------------------------------------------- */

@media (max-width: 34rem) {
  main { padding: 1.5rem 0.85rem 5rem; }

  /* The label column stops paying for itself below about this width -- 6.5rem
     of label leaves too little for the value, and every row wraps to three
     lines. Labels go above their values instead, which keeps the pairing. */
  .facts { grid-template-columns: 1fr; gap: 0.1rem; }
  .facts dt { padding-top: 0.5rem; }
  .facts dd + dt { border-top: 1px solid var(--line); }

  .event { grid-template-columns: 1fr; }
  .event-time { grid-row: auto; }

  .day h3 { gap: 0 0.5rem; }
  .day-sun { margin-left: 0; flex-basis: 100%; }

  .vote { gap: 0.5rem 0.75rem; }
  .vote-agreement { margin-left: 0; flex-basis: 100%; }
}

/* The directions pair, quieter than Website and Menu: those are about the
   place, these are about getting to it, and on a card with four buttons the
   two you press less should recede. */
.btn-map { border-color: var(--line); color: var(--muted); }
.btn-map:hover { background: color-mix(in srgb, var(--muted) 12%, transparent); color: var(--ink); }

/* A place with no street address still gets a map link, beside the admission
   that there is no address. */
.map-fallback { font-size: 0.85em; margin-left: 0.5rem; }

/* The distance row. The verdict is the answer and reads at full strength; the
   numbers behind it are the working, and sit back. */
.journey-verdict { color: var(--ink); }
.journey-detail { color: var(--faint); font-size: 0.88em; }
.journey-detail::before { content: "· "; }

/* --- the gate ------------------------------------------------------------ */

.gate {
  max-width: 22rem;
  margin: 3.5rem auto 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem 1.5rem 1.75rem;
}
.gate h1 { margin-bottom: 0.2rem; }
.gate-why { margin: 0 0 1.25rem; color: var(--muted); font-size: 0.93rem; }

.gate-form { display: flex; flex-direction: column; gap: 0.4rem; }
.gate-label {
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--faint);
}
.gate-input {
  font: inherit;
  padding: 0.5rem 0.65rem;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.gate-input:focus { outline: none; border-color: var(--link); }
.gate-submit {
  font: inherit;
  font-weight: 600;
  margin-top: 0.6rem;
  padding: 0.5rem 0.75rem;
  color: var(--bg);
  background: var(--good);
  border: 1px solid var(--good);
  border-radius: 6px;
  cursor: pointer;
}
.gate-submit:hover { filter: brightness(1.08); }
