/*
 * Owl is read from about two metres, standing, while doing something else.
 * That distance is what sets every size here: a base of 16px is a desk
 * habit, and at two metres it is a grey smudge. Fewer things, bigger.
 *
 * Gap goes on Grid, never on flexbox: flex gap arrived in iOS 14.5 and the
 * ipad's minor version is unknown, while Grid gap has worked since 10.3.
 */

:root {
  /* Day. A cool paper rather than a warm cream: this is an instrument on a
     wall, not a page. */
  --paper:  #f2f2ef;
  --raised: #ffffff;
  --ink:    #17181a;
  --muted:  #6b6f76;
  --line:   #dcdcd6;

  /* The eight a payment or an event can wear.
   *
   * Measured, not eyeballed: the first version had #d2782a and #b99327 at
   * ΔE 7.7 in normal vision — the same colour to anyone standing back, and
   * ΔE 1.8 under deuteranopia — and a teal that read grey. These spread the
   * warm end and lift the teal's chroma: worst pair 10.3, none reads grey.
   *
   * Eight will not pass a chart palette's bar and no set of eight does; the
   * measured ceiling is three. It is acceptable here because the colour is
   * never the only identity — every stripe sits beside its own name. The one
   * place it stands alone is the swatch grid, which is why the worst pair
   * had to move at all. */
  --tag-1: #c0392b;
  --tag-2: #c8700c;
  --tag-3: #9a9016;
  --tag-4: #3f9142;
  --tag-5: #00918d;
  --tag-6: #3a6fbd;
  --tag-7: #8b4fc4;
  --tag-8: #c13a86;

  --step-0: 20px;
  --step-1: 28px;
  --step-2: 40px;
  --step-3: 64px;

  --gap: 20px;
  --edge: 32px;
}

/* Night. The app knows the hour — the ipad's own appearance setting is a
   preference nobody changes twice a day, so it is not the one to read. */
:root[data-light="night"] {
  --paper:  #14161a;
  --raised: #1d2026;
  --ink:    #d9d6d0;
  --muted:  #878c95;
  --line:   #2b2f37;

  /* Chosen against the dark surface, not flipped from the day ones: worst
     pair 9.7 where the old set was 7.5. */
  --tag-1: #e5786e;
  --tag-2: #e2933a;
  --tag-3: #c4b73f;
  --tag-4: #63b95a;
  --tag-5: #25bab1;
  --tag-6: #6ba2f0;
  --tag-7: #b07fe8;
  --tag-8: #ee6fb4;
}

* { box-sizing: border-box; }

/* WHY this is here and not per element: the browser hides [hidden] with
   display:none, and ANY class that sets display — grid, flex — outranks it
   and the element stays on screen while the DOM says it is gone. One rule
   that always wins beats remembering to add [hidden] to each new class. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
}

body {
  background: var(--paper);
  color: var(--ink);
  font: var(--step-0)/1.35 -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  /* A wall display is never text-selected, and a long press that highlights
     a word is only ever an accident. */
  -webkit-user-select: none;
  user-select: none;
  transition: background 600ms linear, color 600ms linear;
}

/* Money and dates are data, not prose: tabular figures line up in a column
   so two amounts compare without being read. */
.tabular {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.app {
  display: grid;
  grid-template-rows: auto 1fr;
  height: 100%;
}

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

/* The two tabs sit together on the left and the clock is pushed to the far
   edge by the fr column between them. */
.bar {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  gap: var(--gap);
  align-items: center;
  padding: var(--edge) var(--edge) 0;
}

.tab, .pill {
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
  /* 44px is the smallest thing a finger hits reliably, and this one gets
     hit with wet hands. */
  min-height: 56px;
  padding: 0 24px;
}

.tab {
  font-size: var(--step-1);
  padding: 0 28px;
}

.tab[aria-selected="true"] {
  color: var(--paper);
  background: var(--ink);
  border-color: var(--ink);
}

.pill[aria-selected="true"] {
  color: var(--ink);
  background: var(--raised);
  border-color: var(--ink);
}

.clock {
  justify-self: end;
  color: var(--muted);
  font-size: var(--step-1);
}

/* ---- page --------------------------------------------------------- */

.page {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--gap) var(--edge) var(--edge);
}

/* ---- pin ---------------------------------------------------------- */

.gate {
  display: grid;
  gap: var(--gap);
  place-content: center;
  justify-items: center;
  height: 100%;
  padding: var(--edge);
}

.gate h1 {
  margin: 0;
  font-size: var(--step-3);
  font-weight: 600;
  letter-spacing: -0.03em;
}

.gate p {
  margin: 0;
  color: var(--muted);
}

.gate input {
  -webkit-appearance: none;
  appearance: none;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: var(--step-2);
  letter-spacing: 0.4em;
  text-align: center;
  color: var(--ink);
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: 12px;
  width: 320px;
  max-width: 100%;
  min-height: 84px;
  padding: 0 16px;
}

.gate input:focus {
  outline: 3px solid var(--tag-6);
  outline-offset: 3px;
}

.enter {
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  font-size: var(--step-1);
  color: var(--paper);
  background: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 12px;
  cursor: pointer;
  min-height: 72px;
  padding: 0 48px;
}

.enter:disabled {
  color: var(--muted);
  background: transparent;
  border-color: var(--line);
  cursor: default;
}

.gate .wrong {
  color: var(--tag-1);
  min-height: 1.35em;
}

/* ---- shared ------------------------------------------------------- */

.empty {
  color: var(--muted);
  font-size: var(--step-1);
  padding: var(--step-2) 0;
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ---- payments ----------------------------------------------------- */

.pills {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: max-content;
  gap: 12px;
  padding-bottom: var(--gap);
}

.rows {
  display: grid;
  gap: 12px;
}

/* A payment is a row with its colour as a stripe, not a block painted in
   it. Nine payments painted whole would be nine blocks competing, and the
   thing that has to be read from two metres is the name. */
.row {
  display: grid;
  grid-template-columns: 6px 1fr;
  gap: 0;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}

.row > .stripe { background: var(--stripe, var(--muted)); }

.row > .body {
  display: grid;
  gap: 6px;
  padding: 18px 24px;
  min-height: 56px;
}

.row .line {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--gap);
  align-items: baseline;
}

.row .name {
  font-size: var(--step-1);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.row .count, .row .when, .row .amount { color: var(--muted); }
.row .amount { font-size: var(--step-1); color: var(--ink); }

/* The soft state of a due date that has gone by. WHY not a red: the due
   date is a reminder, not a bill, and an alarm colour on a screen you pass
   a hundred times a day stops meaning anything by the tenth. The words
   carry it — "venció hace 5 días" against "vence el 20". */
.row.past .when { color: var(--ink); font-weight: 600; }

.row .periods {
  display: grid;
  gap: 2px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.row .period {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--gap);
  align-items: baseline;
  min-height: 48px;
  align-content: center;
}

.row .period .when { font-size: var(--step-0); }

/* The whole row is the target: at two metres you aim at a shape, not at a
   chevron. Only rows that have something to open take a press. */
.row.expandable > .body { cursor: pointer; }

/* The word that both opens the row and says it is open. It reads at a
   distance, which a chevron does not. */
.row .count.opens {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* ---- actions inside an open row ------------------------------------ */

.row .period.payable {
  cursor: pointer;
  padding: 0 4px;
  border-radius: 8px;
}

.row .period .go { color: var(--muted); }

.row .edit {
  justify-self: start;
  margin-top: 6px;
  color: var(--muted);
  background: transparent;
  border: 0;
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 4px;
  min-height: 48px;
  padding: 0;
  cursor: pointer;
}

.add {
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  font-size: var(--step-1);
  color: var(--muted);
  background: transparent;
  border: 1px dashed var(--line);
  border-radius: 14px;
  cursor: pointer;
  width: 100%;
  min-height: 72px;
  margin-top: 12px;
}

/* ---- the form ------------------------------------------------------ */

/* Full screen rather than a dialog: with the keyboard up an ipad leaves
   about 400px, and a seven field form in a centred box would be cut in
   half exactly while being typed into. Creating a payment happens about
   nine times ever, so it can have the screen. */
.form {
  display: grid;
  gap: var(--gap);
  align-content: start;
}

.form-bar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--gap);
  align-items: center;
  padding-bottom: 4px;
}

.form-title {
  justify-self: center;
  font-size: var(--step-1);
  font-weight: 600;
}

.pill.save {
  color: var(--paper);
  background: var(--ink);
  border-color: var(--ink);
}

.field {
  display: grid;
  gap: 8px;
  color: var(--muted);
}

.field.two {
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
}

.field.two label { display: grid; gap: 8px; }

/* The system's own controls: they already know the ipad's keyboard, its
   language and its accessibility settings, and nobody has to learn them. */
.field input, .field select {
  font: inherit;
  font-size: var(--step-1);
  color: var(--ink);
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: 12px;
  min-height: 64px;
  padding: 0 16px;
  width: 100%;
}

.field input:focus, .field select:focus {
  outline: 3px solid var(--tag-6);
  outline-offset: 2px;
}

.swatches {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 12px;
  max-width: 640px;
}

.swatch {
  -webkit-appearance: none;
  appearance: none;
  height: 64px;
  border: 3px solid transparent;
  border-radius: 12px;
  cursor: pointer;
  background: var(--swatch);
}

.swatch[aria-selected="true"] { border-color: var(--ink); }

/* ---- the pay sheet -------------------------------------------------- */

/* A dialog and not a screen: paying is confirming a number that is already
   filled in, so it is one tap and the list behind it stays as context. */
.sheet {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, 0.55);
  padding: var(--edge);
}

.sheet-box {
  display: grid;
  gap: var(--gap);
  width: 520px;
  max-width: 100%;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: var(--edge);
}

.sheet-title {
  margin: 0;
  font-size: var(--step-1);
  font-weight: 600;
}

.sheet-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

/* ---- today --------------------------------------------------------- */

.days { display: grid; gap: var(--gap); }

.day {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: var(--gap);
  align-items: start;
  padding-bottom: var(--gap);
  border-bottom: 1px solid var(--line);
}

/* The date is its own column rather than a heading above: from two metres
   you find the day by scanning one edge, not by reading down the page. */
.day .head {
  display: grid;
  gap: 2px;
  align-content: start;
  padding-top: 14px;
}

.day .weekday {
  font-size: var(--step-1);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.day .number { color: var(--muted); }

/* Today is the only day that gets a mark, and it is the one you came to
   look at. Every other day stays quiet. */
.day.now .weekday { color: var(--tag-6); }

.day .list { display: grid; gap: 8px; }

/* The time column is wide enough for "09:00–17:00" in the tabular face on
   one line. Wrapping it costs a whole extra row of height, which on a
   screen read from two metres is the most expensive thing there is. */
.event {
  display: grid;
  grid-template-columns: 4px 200px 1fr;
  gap: 16px;
  align-items: baseline;
  min-height: 56px;
  align-content: center;
  white-space: nowrap;
}

.event .stripe {
  align-self: stretch;
  border-radius: 2px;
  background: var(--stripe, var(--muted));
}

.event .clock { color: var(--muted); }

/* An all day event says so where the others put a time: the column stays
   aligned and the difference reads without a badge. */
.event .clock.allday { font-style: italic; }

.event .what {
  font-size: var(--step-1);
  font-weight: 500;
}

.day .nothing {
  color: var(--line);
  padding: 14px 0;
}

/* ---- the event form ------------------------------------------------ */

/* Seven toggles instead of a native multi select: a select of weekdays on
   an ipad opens a wheel you scroll one at a time, and the whole point is
   seeing at a glance which days are on. */
.days-picker { grid-template-columns: repeat(7, 1fr); max-width: 560px; }

.days-picker .swatch {
  display: grid;
  place-items: center;
  font: inherit;
  font-size: var(--step-1);
  font-weight: 600;
  color: var(--muted);
  background: var(--raised);
  border: 1px solid var(--line);
}

.days-picker .swatch[aria-selected="true"] {
  color: var(--paper);
  background: var(--ink);
  border-color: var(--ink);
}

/* The only destructive control in Owl, so it is the only one that gets to
   look like one — and it asks before it does anything. */
.danger {
  -webkit-appearance: none;
  appearance: none;
  justify-self: start;
  font: inherit;
  font-size: var(--step-1);
  color: var(--tag-1);
  background: transparent;
  border: 1px solid var(--tag-1);
  border-radius: 12px;
  cursor: pointer;
  min-height: 64px;
  padding: 0 32px;
  margin-top: var(--gap);
}

/* A match is not yours: no stripe, because the stripe means the colour you
   gave something, and nothing here opens when pressed. */
.event.match .stripe { background: transparent; }
.event.match .what { font-weight: 400; }

.event .league {
  margin-right: 12px;
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* ---- metrics -------------------------------------------------------- */

.year {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: var(--gap);
  align-items: center;
  justify-content: start;
  padding-bottom: var(--gap);
}

.year .value {
  font-size: var(--step-2);
  font-weight: 600;
  min-width: 160px;
  text-align: center;
}

.totals { display: grid; gap: 4px; }

/* Each row carries its own share as a bar behind the text. WHY a bar at
   all: from two metres, comparing six numbers is reading and comparing six
   lengths is looking. It is a div with a width, not a chart library. */
.total {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--gap);
  align-items: baseline;
  min-height: 64px;
  align-content: center;
  padding: 0 20px;
  border-radius: 10px;
  overflow: hidden;
}

.total .bar {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--stripe, var(--muted));
  /* Faint on purpose: it is a proportion behind the words, not a mark that
     has to be read on its own. */
  opacity: 0.22;
  border-radius: 0 4px 4px 0;
}

.total .name, .total .amount { position: relative; }
.total .name { font-size: var(--step-1); font-weight: 500; }
.total .amount { font-size: var(--step-1); }

.total.sum {
  margin-top: 12px;
  border-top: 1px solid var(--line);
  border-radius: 0;
  padding-top: 12px;
}

.total.sum .name { color: var(--muted); font-weight: 400; }
.total.sum .amount { font-size: var(--step-2); font-weight: 600; }
