/* The screens and the tab bar, the ring of categories, settings and catalogues, the month grid.
   One of the stylesheets index.html loads IN ORDER: a rule here may rely on coming
   after the files before it. */

/* --- the screens and the tab bar --- */
/* Hiding is a general rule rather than one for two chosen classes. It used to say
   `.screen.is-hidden, .fab.is-hidden`, and the sections inside a screen were not hidden at
   all: the «Limits / Recurring» segment switched while both were on the screen at once. */
.is-hidden { display: none !important; }

/* The bar holds the bottom edge over the content: a thumb reaches it, and it also decides
   how much room is left for the screen. */
.nav {
  position: fixed;
  left: 8px; right: 8px;
  bottom: calc(8px + var(--safe-bottom));
  z-index: 6;
  display: flex;
  justify-content: space-around;
  padding: 8px 4px;
  border-radius: var(--r-sheet);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: var(--edge), 0 6px 24px var(--shadow);
  /* The finger leads the highlight along the bar — the page's scroll has no business here. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

/* The chosen tab's highlight: it travels under the finger and shows where you will land. */
.nav__pill {
  position: absolute;
  top: 6px; bottom: 6px;
  left: 0;
  border-radius: var(--r-card);
  background: color-mix(in srgb, var(--text) 10%, transparent);
  opacity: 0;
  pointer-events: none;
}

.nav__item {
  position: relative;       /* above the highlight */
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 4px 2px;
  color: var(--hint);
  font-size: 11px;
}
.nav__item.is-active { color: var(--text); }
.nav__item.is-hover { color: var(--text); }
.nav__item.is-hover.is-soon { opacity: .6; }
/* Tabs that are not built yet are visible but honestly dimmed. */
.nav__item.is-soon { opacity: .42; }
.nav__item:active { opacity: .6; }
.nav__label { line-height: 1; }

/* --- the ring of categories --- */
.donut {
  position: relative;
  /* The ring is the main thing on the summary screen and is given the upper part; the list
     below scrolls. vw rather than fixed pixels: on narrow screens it will not run out of
     room. */
  width: min(74vw, 300px);
  margin: 14px auto 6px;
  -webkit-touch-callout: none;
  /* none rather than pan-y: a finger on the ring scrubs the segments, and the page's scroll
     has no business here. With pan-y the browser took the gesture for itself at the very
     first movement — the scrub lived exactly until the finger began to move. */
  touch-action: none;
}
/* Explicitly on the SVG too: WebKit does not always narrow a descendant's rights by its
   ancestor's, and an svg's computed touch-action is its own. */
.donut__ring, .donut__ring circle { touch-action: none; }
.donut__ring circle { transition: stroke-width .12s ease, opacity .12s ease; }
.donut__ring { display: block; width: 100%; height: auto; }
.donut__track { opacity: .5; }

.donut__center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* The caption is stretched across the whole ring and must not intercept touches: on the
     summary there are segments underneath it that people tap. */
  pointer-events: none;
}
/* A button inside the caption, on the other hand, must. Without this «set a ceiling» on the
   budget screen could not be pressed by anything at all: not disabled, not covered — simply
   invisible to a finger, because it inherited the transparency from its parent. The rule is
   a general one rather than for a single button: the next one put here would otherwise
   repeat that fate silently. */
.donut__center button { pointer-events: auto; }
.donut__count { font-size: 32px; font-weight: 700; }
.donut__word {
  max-width: 60%;
  font-size: 12px;
  color: var(--hint);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* a category list row: the name on top, the share and the number of operations under it */
/* The row chosen on the ring */
.op.is-picked { background: color-mix(in srgb, var(--accent) 18%, var(--surface)); }

.op__name { display: block; }
/* An ellipsis rather than a hard cut. The caption is one line and is clipped by the
   card's width, and with `text-overflow: clip` it broke off mid-word: «занято до конца
   период». A cut word reads as a bug in the text; an ellipsis reads as «there is more». */
.op__meta {
  display: block;
  font-size: 12px;
  color: var(--hint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The yearly equivalent is quieter than the rest: it is not a fact about the period but its
   continuation («if this keeps up»), and it must not argue with the sum on the right. */
.op__year { display: block; font-size: 11px; color: var(--hint); opacity: .75; }

/* --- the settings and the catalogues --- */

/* The cog lives in the screen's corner rather than in the bar: rarely needed, always in
   place. */
.gear {
  position: fixed;
  top: calc(10px + var(--safe-top));
  left: 12px;
  z-index: 5;
  width: 36px; height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface) 85%, transparent);
  box-shadow: var(--edge);
  color: var(--hint);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.gear:active { opacity: .6; }
.gear--right { left: auto; right: 12px; }
/* The budget's and the analytics' currency: the same corner tile, wide enough for «NOK ⌄».
   It belongs to the top of the screen and leaves with it (the owner, 16.10): floating
   over the list, it covered the sums on the right of every row scrolled under it. */
.gear--chip {
  position: absolute;
  width: auto;
  gap: 5px;
  padding: 0 11px;
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
}

.sheet__label {
  padding: 16px 4px 7px;
  color: var(--hint);
  font-size: 13px;
  letter-spacing: .01em;
}
.sheet__label[hidden] { display: none; }

.sheet__rowtitle { font-size: 16px; }

/* An option in a picker list: the name and, when there is one, an explanation beneath it. */
.sheet__choice { display: flex; flex-direction: column; gap: 2px; text-align: left; }
.sheet__choicehint { color: var(--hint); font-size: 13px; }
.is-current .sheet__choicehint { color: var(--hint); }
.sheet__rowvalue { color: var(--hint); }
/* A tag's spending: «1 434 NOK» broken over two lines reads as two numbers. */
.tagrow__spent { white-space: nowrap; padding-left: 12px; }

/* a quick set of emoji */
.emoji {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 6px;
  padding: 2px 2px 8px;
}
.emoji__item {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  background: var(--bg);
  font-size: 17px;
}
.emoji__item.is-active { background: var(--accent); }
.emoji__item:active { opacity: .6; }
.emoji__input { margin-bottom: 4px; }

/* the colour palette — nine in a row, two rows: eighteen circles ten to a line would be
   smaller than a fingernail, and people miss things that small. */
.swatches {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  gap: 8px;
  padding: 2px 2px 6px;
}
.swatch {
  aspect-ratio: 1;
  border-radius: 50%;
  /* The outline of the chosen one is drawn INWARDS with a shadow rather than as a border
     with scale: an enlarged circle ran out of its cell and was clipped by the sheet's edge. */
  box-shadow: none;
}
.swatch.is-active {
  box-shadow: 0 0 0 2px var(--surface) inset, 0 0 0 3px var(--text);
}

/* an archived category in the list — dimmed, but visible */
.cat.is-archived { opacity: .45; }

/* The search field in sheets that hold lists */
.sheet__field--search { margin: 2px 0 12px; }

/* A dangerous action at the bottom of a form: named in words, not as an icon off to one
   side. */
/* A dangerous action at the bottom of a form. A plaque, like the «Archive it» next to it:
   two buttons in one row must not look like different breeds — the red already tells them
   apart. */
.sheet__danger {
  width: 100%;
  margin-top: 4px;
  padding: 13px;
  border-radius: var(--r-card);
  background: var(--bg);
  color: var(--up);
  font-size: 16px;
}
.sheet__danger:active { opacity: .6; }
/* The same action, but it looks like a button: red text with no border reads as a caption,
   and gives no clue that it will do anything. */
.sheet__danger--framed {
  box-shadow: inset 0 0 0 1px var(--up);
  font-weight: 600;
}

/* An import rule's card. */
.rulecard__key {
  font-size: 19px;
  font-weight: 700;
  padding: 4px 4px 10px;
  word-break: break-word;
}
.rulecard__warn {
  margin: 4px 0 10px;
  padding: 10px 12px;
  border-radius: var(--r-card);
  background: color-mix(in srgb, var(--up) 12%, transparent);
  color: var(--up);
  font-size: 13px;
  line-height: 1.35;
}
/* The rule says one thing and the operations sit in another — and that is fixed in one tap. */
.rulecard__fact {
  margin: 10px 0;
  padding: 12px;
  border-radius: var(--r-card);
  background: var(--bg);
}
.rulecard__facttext {
  font-size: 13px;
  line-height: 1.35;
  margin-bottom: 10px;
}
.rulecard__take {
  width: 100%;
  padding: 10px;
  border-radius: var(--r-field);
  background: var(--accent);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
}
.rulecard__take:active { opacity: .8; }

.rulecard__samples {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 10px;
}
.rulecard__sample {
  font-size: 13px;
  color: var(--hint);
  font-variant-numeric: tabular-nums;
  word-break: break-word;
}

/* The column's chosen role: a tick and the accent, so it does not have to be hunted for. */
.row.is-chosen .row__title { color: var(--accent); font-weight: 600; }
.row.is-chosen { color: var(--accent); }

/* --- picking a month from a grid --- */
.yearbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.yearbar__year {
  flex: 1;
  text-align: center;
  font-size: 17px;
  font-weight: 700;
}
.yearbar__arrow {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: var(--hint);
}
.yearbar__arrow:active { opacity: .5; }
/* A year past the edge of the history: the arrow is in place but switched off — that way it
   is clear there is nowhere further to go, and the row does not jump from a vanished
   button. */
.yearbar__arrow:disabled { opacity: .25; }
.yearbar__arrow:disabled:active { opacity: .25; }
/* The forward arrow is the same icon turned around: there is no separate one in the set. */
.yearbar__arrow--next { transform: rotate(180deg); }

.monthgrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.monthgrid__item {
  padding: 14px 0;
  border-radius: var(--r-field);
  background: var(--bg);
  font-size: 15px;
}
.monthgrid__item:active { opacity: .6; }
/* A month outside the history: it is visible that it exists, but there is nothing to open
   there. */
.monthgrid__item:disabled {
  opacity: .3;
  background: transparent;
}
.monthgrid__item:disabled:active { opacity: .3; }
.monthgrid__item.is-active {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}
/* The current month: a fixed point when you are flicking through other years. */
.monthgrid__item.is-now:not(.is-active) {
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--accent);
}

/* The month failed to load: the header names the chosen month, the content is empty. */
.deck__failed {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 0 24px;
  text-align: center;
  color: var(--hint);
  font-size: 13px;
}

/* The import rules: a header «how many · wipe them all», with the search and the filter
   below. */
.rules__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.rules__count { margin: 0; }
.rules__clear {
  flex: 0 0 auto;
  padding: 7px 14px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--up);
  color: var(--up);
  font-size: 14px;
  font-weight: 600;
}
.rules__clear:active { opacity: .6; }

/* The search and the filter stick to the header: there are three hundred rules, and without
   this, once you had scrolled down, getting back to the search field meant scrolling the
   whole list. */
.rules__bar {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 10px;
  margin-bottom: 0;
  background: var(--surface);
}
.rules__search { flex: 1 1 auto; min-width: 0; margin: 0; }
.rules__kind {
  flex: 0 0 auto;
  padding: 11px 14px;
  border-radius: var(--r-field);
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  white-space: nowrap;
}
.rules__kind:active { opacity: .6; }
/* The filter is on — it is visible that the list is not showing everything. */
.rules__kind.is-active {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}

/* The import rules: a «shop → category» row with a cross on the right. */
.rules { display: flex; flex-direction: column; }
.rule {
  display: flex;
  align-items: center;
  gap: 8px;
}
.rule + .rule { border-top: 1px solid var(--line); }
.rule__main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 12px 4px;
  text-align: left;
}
.rule__main:active { opacity: .6; }
.rule__match {
  font-size: 15px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rule__cat { font-size: 12px; color: var(--hint); }
/* The rule points at a category that does not exist: from the outside it looks healthy,
   while during an import it will silently send the operations into «Other». */
.rule__cat.is-broken { color: var(--up); }
.rule__drop {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: var(--hint);
}
.rule__drop:active { opacity: .5; }

/* Archiving and deleting share one row under «Save». */
.sheet__actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}
.sheet__actions > * {
  flex: 1;
  min-width: 0;
  margin-top: 0;
  padding: 13px 8px;
  font-size: 15px;
  /* A long label («Archive it · 12 ops.») does not fit into half the width, and a line
     break would break the row's height. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- a wide screen: the same screen, its two halves side by side ---
   Every tab is «what the period is» over «the list and its filters» (deck.js, columns).
   On a phone the halves' wrappers vanish from the layout; from a landscape tablet up
   they stand left and right, and everything that lives in a corner of the phone's screen
   lives in the same corner of the app's frame — not of a window that may be stretched to
   any width. The sheets and the bar keep a phone's width: they are things to read and
   to tap, and a 1 200-pixel keypad or tab bar helps nobody. */
.screen__side, .screen__main { display: contents; }

/* The month's categories under the chart (monthcats.js): a wide screen's only. */
.mcats-slot { display: none; }
.mcats {
  margin-top: 14px;
  padding: 10px 12px;
  border-radius: var(--r-card);
  background: var(--surface);
  box-shadow: var(--edge);
}
.mcats__title { font-size: 13px; color: var(--hint); margin-bottom: 4px; }
.mcats__row {
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) 76px;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  margin: 0 -8px;
  border-radius: var(--r-field);
  text-align: left;
  cursor: pointer;
}
.mcats__row:hover { background: color-mix(in srgb, var(--text) 5%, transparent); }
.mcats__row.is-active { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.mcats__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mcats__emoji { margin-right: 8px; }
.mcats__bar { height: 6px; border-radius: 3px; background: color-mix(in srgb, var(--text) 8%, transparent); overflow: hidden; }
.mcats__bar i { display: block; height: 100%; border-radius: 3px; }
.mcats__sum { font-variant-numeric: tabular-nums; font-weight: 600; text-align: right; }
.mcats__more { padding: 6px 0 0; font-size: 13px; color: var(--hint); }

@media (min-width: 900px) {
  :root {
    --frame: min(1180px, calc(100vw - 48px));
    --frame-edge: calc((100vw - var(--frame)) / 2);
    --column: 560px;
    /* The list's half: the right one of the two columns below. */
    --main-column: calc((var(--frame) - 32px) * 1.1 / 2.1);
  }
  #app { width: var(--frame); margin: 0 auto; }
  .screen {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    gap: 0 32px;
    align-items: start;
  }
  /* The figure and the chart stay in view while the list scrolls past them. */
  .screen__side { display: block; position: sticky; top: 0; min-width: 0; }
  .mcats-slot { display: block; }
  /* The summary's ring in the middle of the screen's height, not pressed to the top. */
  .screen--middle .screen__side {
    min-height: calc(100vh - 100px - var(--safe-bottom));
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  /* The budget and the analytics: the phone's one column, a little wider, in the middle. */
  .screen--single { display: block; max-width: 640px; margin: 0 auto; }
  /* Down past the corner tiles, level with the chart under the figure. */
  .screen__main { display: block; min-width: 0; padding-top: 56px; }

  .gear { left: calc(var(--frame-edge) + 4px); }
  .gear--right { left: auto; right: calc(var(--frame-edge) + 4px); }
  .fab { right: calc(var(--frame-edge) + 12px); }
  .nav {
    left: calc(50% - var(--column) / 2);
    right: calc(50% - var(--column) / 2);
  }
  /* Sheets rise from the bottom as on a phone, a column's width, in the middle. */
  .sheet__backdrop { justify-content: center; }
  .sheet { max-width: 640px; }

  /* The entry form and what opens from it stand IN the screen: in the left column, from
     its foot up, over the categories (sheet.js, `inline`) — a card of the screen rather
     than a panel rising from the window's edge. Nothing is veiled: the figure, the bank
     check and the feed on the right stay alive. The form placed over another hides it. */
  .sheet__backdrop.is-placed,
  .sheet__backdrop.is-placed.is-open {
    right: auto;
    top: 12px;
    bottom: calc(84px + var(--safe-bottom));
    padding: 0;
    align-items: flex-end;
    background: transparent;
    /* Only the card takes clicks: past it the bank check and the feed answer as usual.
       The cross and Esc close it. */
    pointer-events: none;
  }
  .is-placed .sheet { pointer-events: auto; }
  .is-placed .sheet {
    max-width: none;
    max-height: 100%;
    border-radius: var(--r-sheet);
    padding-bottom: 16px;
    box-shadow: var(--edge), 0 12px 32px -8px var(--shadow);
    opacity: 0;
    transform: translateY(12px);
    transition: transform .22s cubic-bezier(.2, .8, .3, 1), opacity .16s ease;
  }
  .is-placed.is-open .sheet { opacity: 1; transform: none; }
  .is-placed .sheet__grip { display: none; }
  .sheet__backdrop.is-placed:has(~ .sheet__backdrop.is-placed) .sheet { visibility: hidden; }
  body.has-placed [data-sheet-anchor] { visibility: hidden; }
  /* Beside the feed the check need not keep the chart's height: nothing under it jumps. */
  .chart--feed .shows-balance .bal-check { min-height: 0; }
}
