/* ============================================================
   WroomWroom — page styles
   Entry point. Loads the tokens, then the component layer, then
   the page-specific rules below.

   Order matters: rules here load AFTER components.css and will
   win on equal specificity. Keep that deliberate — scope page
   rules to intent (.hero-body p) rather than reaching for
   specificity, which only moves a collision rather than fixing it.
   ============================================================ */

@import url("tokens/colors.css");
@import url("tokens/typography.css");
@import url("tokens/spacing.css");
@import url("tokens/effects.css");
@import url("components.css");

/* ---------- Reset ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The browser hides [hidden] with a `display: none` rule of the lowest
   possible weight, so any class that sets `display` beats it and the
   attribute silently stops working. This caught the sign-in gate: it has
   `display: flex`, so hiding it did nothing and the gate and the ledger
   were on screen together. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-body);
  font: var(--font-body);
  -webkit-font-smoothing: antialiased;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

button,
input,
select {
  font-family: inherit;
}

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--surface-card);
  border-bottom: 1px solid var(--border-subtle);
}

/* 4.5rem, not 3.5. At 3.5 the band was 56px with the name set at body size
   — a title no larger than the figures in the table under it, which read as
   an accident rather than as restraint. */
.site-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  min-height: 4.5rem;
}

.site-title {
  margin: 0;
  font: inherit;
}

/* The wordmark is set in mono: this is a ledger, and the name is as
   much a label as everything else on the page. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  font: var(--font-value);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
  color: var(--text-strong);
  text-decoration: none;
}

/* A Zastava 750 from the side, drawn in one weight like the burger and
   the pencil. It replaced a red-and-teal bar — the balance graph in
   miniature — which stopped meaning anything once the I alt bar it
   echoed was taken off the page. See UI.md.

   The consequence, accepted: the two ledger colours no longer meet
   anywhere outside the graph itself. */
.wordmark-mark {
  display: inline-flex;
  width: 3.2rem;
  height: 1.6rem;
  flex: none;
}

.wordmark-mark svg {
  width: 100%;
  height: 100%;
}



.site-header-right {
  display: flex;
  align-items: center;
  gap: var(--space-5);
}

/* ---------- The header menus ---------- */
/* Two of them: which people you want to see, and your account. They
   share their panel and their behaviour — see js/views/dropdown.js,
   which also keeps only one of them open at a time. */
.menu {
  position: relative;
  display: flex;
}

.burger {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--control-height);
  height: var(--control-height);
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease);
}

.burger:hover,
.burger:focus-visible,
.burger[aria-expanded="true"] {
  color: var(--color-accent);
}

/* Three hairlines of the same weight as every border on the page, rather
   than bringing in an icon set for one control. */
.burger-bars {
  position: relative;
}

.burger-bars,
.burger-bars::before,
.burger-bars::after {
  display: block;
  width: 1.05rem;
  height: 1.5px;
  border-radius: 1px;
  background: currentColor;
}

.burger-bars::before,
.burger-bars::after {
  content: "";
  position: absolute;
  left: 0;
}

.burger-bars::before {
  top: -0.36rem;
}

.burger-bars::after {
  top: 0.36rem;
}

/* Your initials, and behind them the way out.

   A circle the size of the burger, so the two read as a pair of controls
   rather than a control and a label. Three characters of mono at the
   small size sit comfortably inside it. */
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--control-height);
  height: var(--control-height);
  padding: 0;
  border: 1px solid var(--border-input);
  border-radius: 50%;
  background: none;
  font: var(--font-label);
  font-size: var(--text-xxs);
  letter-spacing: 0.02em;
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease);
}

.avatar:hover,
.avatar:focus-visible,
.avatar[aria-expanded="true"] {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

/* Flat, like the rest: a hairline and the card surface. The token file
   carries no elevation or blur deliberately, so a floating panel is
   separated by its border and nothing else. */
.menu-panel {
  position: absolute;
  top: calc(100% + var(--space-3));
  right: 0;
  z-index: 20;
  min-width: 11rem;
  padding: var(--space-4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  background: var(--surface-card);
}

.menu-label {
  margin: 0 0 var(--space-3);
  font: var(--font-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* A column, unlike the passenger row it borrows its controls from: this
   is a list to read down, and the header has no width to spare. */
.people-menu .check-group {
  flex-direction: column;
  align-items: stretch;
}

.people-menu .check {
  align-self: stretch;
}

/* Wider than the people list: an address is longer than a set of
   initials, and wrapping it mid-domain would be worse than the width. */
.account-menu {
  min-width: 14rem;
}

.account-email {
  margin: 0 0 var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
  color: var(--text-body);
  overflow-wrap: anywhere;
}

.account-menu .btn-quiet {
  width: 100%;
}

/* ---------- The balance axis ---------- */
/* The signature.

   Five rows growing from one shared centre line: credit rightward,
   debt leftward, one scale for all of them. That is what makes them
   comparable at a glance rather than five figures read in turn, and
   it is the one place the ledger colours run at full strength —
   which is why everything around them stays quiet. */
/* ---------- Sign-in gate ---------- */
/* Deliberately plain. It says what the site is and offers one control;
   there is nothing to read here and nothing to decide. */
.gate {
  display: flex;
  justify-content: center;
  padding: calc(var(--rhythm) * 3) 0;
}

/* Sized so the panel, not the controls, holds the space. */
.gate-card {
  width: min(22rem, 100%);
  padding: calc(var(--rhythm) * 1.6) calc(var(--rhythm) * 1.4);
}

.gate-form {
  display: grid;
  gap: var(--space-4);
}

.gate-card .btn-primary {
  width: 100%;
  margin-top: var(--space-2);
}

/* Quiet, and centred under the button: it is the way out of a problem, not
   a second thing to choose between. */
.gate-forgot {
  justify-self: center;
}

/* The card's buttons run its full width — see .btn-primary above — so this
   one does too rather than floating at whatever width its label happens to
   be. It is the only control on the card it belongs to. */
.gate-action {
  width: 100%;
}

.gate-body {
  margin: 0 0 var(--space-5);
  color: var(--text-body);
  font-size: var(--text-sm);
}

/* Only ever visible on localhost. Loud enough that a faked session cannot
   be mistaken for a real one. */
.dev-notice {
  margin: 0;
  padding: var(--space-2) var(--gutter);
  background: var(--color-warn);
  color: var(--color-ink);
  font: var(--font-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  text-align: center;
}

/* ---------- The overview: the standing beside your own figures ---------- */
/* Two things you look at, so they sit together. The form used to hold the
   second column, which was the wrong pairing: a form is something you do,
   twice a week, next to something you read every day.

   3 to 2 rather than even halves. The graph needs the room — it is the one
   memorable thing on the page — and four label-and-figure rows given half
   of 960px only push their labels away from their numbers. */
.overview {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: var(--rhythm);

  /* Both cards take the height of the taller, so the row reads as one band
     rather than two panels of different sizes.

     Safe now, and it was not before: stretching a card used to spread its
     contents into the extra height, because the card was a flex column with
     `flex: 1` inside it, and the balance rows drifted apart whenever the
     other card grew. Nothing inside claims the spare height any more, so a
     stretched card is simply a taller card with its content at the top. */
  align-items: stretch;
}

/* ---------- Opening the form ---------- */
/* Recording a trip is done twice a week, so the form is not furniture:
   it lives in a dialog behind this button, which sits between the
   standing and the history — after the thing you came to look at, and
   before the thing you would scroll past.

   The two once sat side by side, on the argument that recording a trip
   and seeing where it leaves you were one glance. That held while the
   form was always open; behind a button it has nothing to hold. */
.add-trip {
  display: flex;
  justify-content: center;

  /* 1.8 rather than 1, so it sits between the two cards rather than under
     the first one. What follows it is not a margin but this section's
     bottom padding plus the next one's top — 1.2 + 0.8 = two rhythms — so
     an even-looking gap above has to be nearly twice what it appears. The
     remaining fifth of a rhythm leaves it a shade nearer the table it
     leads to, which is the direction it points. */
  margin-top: calc(var(--rhythm) * 1.8);
}

.axis-rows {
  display: grid;
  gap: var(--space-3);
}

.axis-row {
  display: grid;
  grid-template-columns: 3.25rem 1fr 4.5rem;
  align-items: center;
  gap: var(--space-3);
}

/* The initials label the rows; the bars and figures carry the
   meaning. Keeping the names a step back stops five repeated
   three-letter blocks competing with what they point at. */
.axis-name {
  font: var(--font-value);
  letter-spacing: 0.04em;
  color: var(--text-body);
}

/* Someone who no longer rides recedes: the whole row fades, bar
   included. Previously only the name and figure dimmed while the bar
   stayed at full strength, so the rows that mattered least were the
   most colourful thing in the graph. They stay legible, and they stay
   in the total — leaving the carpool does not settle the account. */
.axis-row.is-inactive {
  opacity: 0.4;
}

/* The track carries the zero line. Everything is measured from it. */
.axis-track {
  position: relative;
  height: 1.4rem;
  background: var(--surface-sunken);
  border-radius: 2px;
}

.axis-track::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -0.15rem;
  bottom: -0.15rem;
  width: 1px;
  background: var(--border-input);
}

/* --w is the bar's length as a percentage of half the track,
   set per row from the data. */
.axis-bar {
  position: absolute;
  top: 0.25rem;
  bottom: 0.25rem;
  width: calc(var(--w, 0%) / 2);
  border-radius: 1px;
  transition: width var(--dur) var(--ease);
}

.axis-bar.is-credit {
  left: 50%;
  background: var(--color-credit);
}

.axis-bar.is-debt {
  right: 50%;
  background: var(--color-debt);
}

.axis-value {
  text-align: right;
}

/* ---------- The form inside the dialog ---------- */

/* Flex rather than grid: a grid distributes spare height among its rows,
   which spread the fields apart whenever the form was given more room than
   it needed. That was written when the form shared a stretched row with the
   standing; it holds here too, since a dialog can be taller than its
   contents. */
.trip-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.trip-form-row {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
}

.trip-form-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* ---------- History ---------- */
/* The history sits in a card like the other two panels, so all three
   headings live inside the thing they name rather than one floating
   above it. That inconsistency is easy to miss on a wide screen and
   obvious on a phone, where the three stack into one column. */
.history-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

/* Inside a card the table drops its own frame — the card provides it,
   and two nested borders read as a mistake. */
.card > .table {
  border: 0;
  border-radius: 0;
  background: transparent;
}

/* "I bilen" gets double the width of the others. It can hold five sets
   of initials; the rest hold a date, one word and one control, and
   letting the browser divide the row evenly gave the widest column the
   same room as the narrowest. */
/* Passagerer takes the room, because it is the column that varies: a date
   is a date, a mark is a mark and Chauffør holds exactly one name, but the
   back of the car can hold one or four. */
.table-trips th:nth-child(1) {
  width: 16%;
}

.table-trips th:nth-child(2) {
  width: 13%;
}

.table-trips th:nth-child(3) {
  width: 45%;
}

.table-trips th:nth-child(4) {
  width: 18%;
}

.table-trips th:nth-child(5) {
  width: 8%;
}

/* The mark sits at the right of its column, next to the pencil, so the two
   things that are not the trip itself keep to the same end of the row. */
.table-trips th:nth-child(4),
.table-trips td:nth-child(4) {
  text-align: right;
}

/* Hard against the table's right edge. A row action belongs at the end of
   the row, not adrift in the middle of the space its column happens to
   have. */
.table-trips td:last-child {
  text-align: right;
}

/* Editing is the rare action. Quiet text that wakes up when you are
   on the row, rather than a button repeated down the right edge
   pulling harder than the trips themselves. Always present, so it
   stays reachable by keyboard and on a touch screen. */
.row-action {
  border: 0;
  background: none;
  padding: 0;
  font: var(--font-value);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease);
}

.table tbody tr:hover .row-action,
.row-action:focus-visible {
  color: var(--color-accent);
}

/* An icon-only control is a small thing to hit. The padding takes the
   target to 40px around a 16px drawing — near the 44 usually asked for on
   touch, and as far as the row height allows — while the matching negative
   margin keeps the column laid out as though the button were the icon.

   vertical-align, because an inline-flex box otherwise sits on the text
   baseline and rides a few pixels above the date beside it. */
.row-action.is-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-3);
  margin: calc(var(--space-3) * -1);
  vertical-align: middle;
}

/* display: block, or the inline SVG sits on the text baseline and leaves a
   gap beneath it that pushes the pencil off the row's centre line. */
.row-action.is-icon svg {
  display: block;
  width: 1rem;
  height: 1rem;
}

.riders {
  display: inline-flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* A person and their figure travel together, so the gap between two people
   is wider than the gap between a person and their own number. */
.rider-entry {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35em;
  white-space: nowrap;
}

/* What the trip did to this person. Lighter than the initials and muted,
   so the names stay the thing you read and the figures are there when you
   look for them.

   Not coloured by sign: teal and red mean *you* in this table, and spending
   them on every figure would leave nothing to say which name is yours.
   400 is as thin as the page gets — only 400, 500 and 600 are loaded, and
   fetching a lighter face for one purpose is not worth the request. */
.rider-delta {
  font-weight: var(--weight-regular);
  font-size: var(--text-xxs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.rider {
  font: var(--font-value);
  letter-spacing: 0.04em;
}

/* Everybody else is plain, in both columns. Which role a name has is read
   from the column it sits in, so colour is not needed to say it — and a
   table where every driver was teal spent the ledger's colours on a fact
   the heading already gave. */
.rider.is-driver,
.rider.is-passenger {
  color: var(--text-body);
}

/* Your own name is the only colour in the table, and it means what it means
   in the bars: teal for a trip you drove and are owed for, red for one you
   rode and owe. Scanning the column for the colour answers "how did I do"
   without reading a single name.

   UI.md notes the tension — the bars are meant to be the one place these
   colours run at full strength. At most one coloured word in a row, saying
   something the row does not otherwise say, is judged to earn it. */
.rider.is-you {
  font-weight: var(--weight-semibold);
}

.rider.is-driver.is-you {
  color: var(--color-credit);
}

.rider.is-passenger.is-you {
  color: var(--color-debt);
}

/* Out and back, or one leg only.

   Marks rather than the words T/R and Enkeltur: the column repeats the
   same pair down every row, and what it says is directional, so an
   arrow carries it faster than a word does. The workbook's own names
   are not lost — they stay in DOMAIN.md and in each mark's accessible
   name. Nothing ever stored the string "T/R"; a trip stores oneLeg, so
   this was always a matter of display.

   The round trip is the font's own `⇄`. The one leg is drawn, because
   the font gives `→` only 11px of ink against 14 — visibly shorter in
   a column that repeats them. See js/views/history.js.

   A little heavier than the surrounding type: at this size the arrows
   thinned out against the dates beside them. The weight has to come from
   the font, since that is the only thing that can thicken a glyph, and
   the drawn arrow's stroke is matched to it by eye. */
.trip-mark {
  font: var(--font-value);
  font-size: 1.05rem;
  font-weight: var(--weight-semibold);
  line-height: 1;
  color: var(--text-muted);
}

/* 14 x 8 at this font size, which is the measured ink of `⇄`. Left on
   the baseline deliberately: an inline SVG sits with its bottom edge
   there, so an 8-high box centres 4 above it — exactly where both
   characters' ink sits. In em, so it follows the type rather than
   pinning itself to one size. */
.trip-mark svg {
  width: 0.84em;
  height: 0.48em;
  vertical-align: baseline;
}

/* ---------- The trip dialog ---------- */
/* One form, two jobs — adding, and correcting the trip whose pencil you
   pressed. A native <dialog>, so focus stays inside it, Escape closes it
   and the backdrop is the browser's rather than ours. */
.trip-dialog {
  width: min(32rem, calc(100vw - var(--gutter) * 2));
  padding: calc(var(--rhythm) * 1.4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  background: var(--surface-card);
  color: var(--text-body);
}

/* The one place the page dims itself. Kept to the brand ink rather than
   black, so the page behind reads as covered rather than switched off. */
.trip-dialog::backdrop {
  background: rgb(11 42 58 / 0.45);
}

.trip-dialog .card-title {
  margin-bottom: var(--space-5);
}

/* Slet sits away from Gem, so the destructive one is not next to the one
   you meant. */
.trip-form-actions {
  justify-content: space-between;
}

/* ---------- Dine tal ---------- */
/* Your own figures, folded away.

   They answer something you ask once — how much have I actually driven —
   rather than every time the page opens, so they start closed and the
   balances keep the card. A native <details>: the disclosure, the keyboard
   handling and find-in-page all come free, and nothing here reimplements a
   button badly. */
/* Was a collapsed <details> inside the standing card. Nobody opens a
   disclosure twice, and the figures are the second most interesting thing
   on the page, so they were promoted to a card rather than left folded
   away. The page gains no furniture by it: a card replaced a disclosure. */
.own-stats-list {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
}

.own-stats-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.own-stats-row dt {
  font-size: var(--text-sm);
  color: var(--text-body);
}

/* Lighter than the balances above. `.num` carries the medium weight, which
   is right in the graph where the figure is the whole point; four counts
   set that way only shout at the labels beside them. */
.own-stats-row dd {
  margin: 0;
  font-weight: var(--weight-regular);
  color: var(--text-body);
}

/* ---------- More trips ---------- */
/* How much is showing, and the way past the rest of it. Scrolling to this
   block is what loads the next five, so it is also the thing being watched
   — which is why it stays put once everything is shown, holding the count,
   rather than vanishing and taking the answer with it. */
.history-more {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}

/* ---------- Responsive ---------- */
/* The token file documents these numbers; custom properties do
   not work inside @media, so they are repeated here by necessity. */
@media (max-width: 880px) {
  /* Stacked in markup order: the standing, then your figures, then the
     button, then the history — which is the order they are wanted in. */
  .overview {
    grid-template-columns: 1fr;
  }

  .table {
    display: block;
    overflow-x: auto;
  }
}

@media (max-width: 560px) {
  .axis-row {
    grid-template-columns: 2.75rem 1fr 4.25rem;
    gap: var(--space-2);
  }

  .site-header-inner {
    gap: var(--space-3);
  }

  .history-head {
    flex-direction: column;
    align-items: flex-start;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
