/* Sheets, and entering an operation.
   One of the stylesheets index.html loads IN ORDER: a rule here may rely on coming
   after the files before it. */

/* --- the sheets --- */
.sheet__backdrop {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: flex-end;
  background: rgba(0, 0, 0, 0);
  transition: background .2s ease;
}
.sheet__backdrop.is-open { background: rgba(0, 0, 0, .5); }

.sheet {
  width: 100%;
  /* The side strips inside are wider than the panel (they deliberately run out under its
     padding) — without this the whole sheet scrolled sideways together with the keyboard.

     `clip` rather than `hidden`: a hidden scroll is still something the browser can perform
     by itself. It only took landing in the description field at the right edge for it to
     nudge the panel sideways to reveal the caret: the segments and the keyboard slid left
     with nothing to bring them back. `clip` makes the box unscrollable altogether. */
  overflow-x: clip;
  /* Percentages rather than vh: Telegram shrinks the window itself under the keyboard, the
     inset:0 backdrop shrinks with it, and the panel is measured from the backdrop. With vh
     the panel would measure the whole screen, keyboard included. */
  max-height: 82%;
  display: flex;
  flex-direction: column;
  padding: 8px 16px calc(20px + var(--safe-bottom));
  border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  background: var(--surface);
  /* The surface continues below the edge: on the spring's overshoot the panel rises a
     few pixels, and without this a strip of the screen behind would flash under it. */
  box-shadow: 0 60px 0 0 var(--surface);
  transform: translateY(100%);
  /* A spring: it rises a touch past its place and settles back. */
  transition: transform .34s cubic-bezier(.2, .9, .3, 1.08);
}
.is-open .sheet { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .sheet { transition: none; } }

.sheet__grip {
  width: 36px; height: 4px;
  margin: 0 auto 10px;
  border-radius: 2px;
  background: var(--hint);
  opacity: .4;
}
/* A sheet that cannot be swiped away (the import): the handle is shown pale — it no longer
   promises a gesture, but a hole where it used to be would look broken. */
.sheet__grip.is-flat { opacity: .16; }

/* The header is a grid [spacer · title · button]: that way the button is not clipped by the
   edge and the title sits exactly in the centre whether or not there is a button. The
   background is opaque — the content travels UNDER the header rather than blending into it. */
.sheet__title {
  display: grid;
  grid-template-columns: 36px 1fr 36px;
  align-items: center;
  padding-bottom: 10px;
  text-align: center;
  font-size: 16px;
  font-weight: 600;
  background: var(--surface);
}
.sheet__titletext {
  grid-column: 2;
  /* The title names the operation, and descriptions can be long: it is clipped to one line
     rather than wrapped — the header must stay one height. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sheet__body {
  overflow-x: clip;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Scrolled to the end and the gesture ends there rather than travelling into the page
     behind the sheet. The other half of the defence lives in sheet.js: when there is
     nothing to scroll inside, the movement is cancelled outright. */
  overscroll-behavior: contain;
  /* Room above the first block: sheet.js nudges the scroll a pixel off the edge on touch
     (so WebKit keeps the gesture inside), and with no padding that pixel was cut off the
     top of the first control — the entry sheet's expense/income switch. */
  padding-top: 4px;
}

.sheet__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 14px 4px;
  text-align: left;
  font-size: 16px;
}
.sheet__row + .sheet__row { border-top: 1px solid var(--line); }
.sheet__row:active { opacity: .6; }
/* A row that is not pressed: it must not answer a touch like a button. */
.sheet__row--static:active { opacity: 1; }
.sheet__row.is-current { color: var(--accent); }
.sheet__choiceicon { flex: 0 0 auto; color: var(--hint); }
.sheet__choiceicon + .sheet__choice { margin-right: auto; }
.sheet__row.is-current .sheet__choiceicon { color: inherit; }
/* A row as a plaque: in the profile there are switches next to it, and linear rows mixed in
   with plaques read as two different lists on one screen. */
.sheet__row--card {
  margin-top: 10px;
  padding: 12px 14px;
  border-radius: var(--r-card);
  background: var(--bg);
}
.sheet__row--card + .sheet__row--card { border-top: none; }
.sheet__check { color: var(--accent); }

.sheet__line {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 4px;
}

.sheet__field { position: relative; flex: 1 1 auto; min-width: 0; }

.sheet__input {
  width: 100%;
  padding: 12px 36px 12px 14px;   /* room on the right for the cross */
  border: 1px solid var(--line);
  border-radius: var(--r-field);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 16px;          /* below 16px iOS zooms the page on focus */
  -webkit-appearance: none;
  appearance: none;
  outline: none;            /* the system blue outline is foreign to this theme */
}
.sheet__input:focus { border-color: var(--accent); }
/* A budget amount: the number is the whole point of the sheet, so it is large and centred. */
.sheet__input--amount {
  padding: 14px;
  text-align: center;
  font-size: 28px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.sheet__input--amount::placeholder { font-size: 17px; font-weight: 400; }
.sheet__input::placeholder { color: var(--hint); }

.sheet__clear {
  position: absolute;
  top: 50%; right: 7px;
  transform: translateY(-50%);
  width: 24px; height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface);
  color: var(--hint);
  font-size: 12px;
}
.sheet__clear[hidden] { display: none; }
.sheet__clear:active { opacity: .6; }

.sheet__submit {
  flex: 0 0 auto;
  /* inline-flex, so the button can carry an icon beside its label and the label sits on the
     same line as the text rather than slipping a pixel down. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 6px;
  padding: 14px 18px;
  border-radius: var(--r-card);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 16px;
  font-weight: 600;
  white-space: nowrap;
}
.sheet__submit:active { opacity: .8; }

/* --- entering and editing an operation --- */

/* The «+» button floats over the feed: entry must be within a finger's reach, not a
   scroll's. */
.fab {
  position: fixed;
  right: 16px;
  bottom: calc(86px + var(--safe-bottom));
  z-index: 5;
  width: 56px; height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* A rounded square like the keys and the icons — a circle was the one odd shape. */
  border-radius: 18px;
  background: var(--accent-face);
  color: var(--on-accent);
  font-size: 30px;
  line-height: 1;
  box-shadow: 0 8px 22px -6px color-mix(in srgb, var(--accent) 55%, transparent),
              0 2px 6px var(--shadow);
}
.fab:active { transform: scale(.94); }
/* Moved out of the way while scrolling down. Not display: none — that would make its return
   look like a flash, whereas this way it slides past the edge. */
.fab.is-away {
  transform: translateY(calc(100% + 96px));
  opacity: 0;
  pointer-events: none;
}
.fab { transition: transform .18s ease, opacity .18s ease; }
@media (prefers-reduced-motion: reduce) { .fab { transition: none; } }
.fab svg { display: block; }

.sheet--tall { max-height: 94%; }
.sheet--tall .sheet__body { padding-bottom: 6px; }
.sheet--tall .sheet__body { user-select: none; -webkit-user-select: none; }

.sheet__title { position: relative; }
.sheet__action {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--bg);
  color: var(--hint);
}
.sheet__action.is-danger { color: var(--up); }
/* The way out of a sheet that cannot be swiped away is on the left, where habit looks for
   it. */
.sheet__action--lead { grid-column: 1; justify-self: start; }
.sheet__action:active { opacity: .5; }

/* the «expense / income» switch */
.seg {
  display: flex;
  gap: 4px;
  padding: 3px;
  border-radius: var(--r-field);
  background: var(--bg);
  box-shadow: var(--edge);
}
.seg__item {
  flex: 1;
  padding: 9px;
  border-radius: 11px;
  color: var(--hint);
  font-size: 15px;
  font-weight: 600;
}
.seg__item.is-active { background: var(--surface); color: var(--text); box-shadow: var(--lift); }

/* The chosen kind of operation is coloured: an expense red, an income in the accent (the
   colour income wears everywhere), a transfer blue. Visible out of the corner of the eye without reading the labels.

   The fill is even and faint rather than a glow from below: the gradient was more
   noticeable than the amount itself and stood out from the rest of the interface, where
   colour always lies in an even tone (the chips, the budget rows). The tone is the same as
   an active chip's — 16% of paint over the surface, plus the label in the colour itself. */
.seg__item.is-active.seg__item--expense,
.seg__item.is-active.seg__item--income,
.seg__item.is-active.seg__item--transfer {
  background: color-mix(in srgb, var(--seg-tint) 16%, var(--surface));
  color: var(--seg-tint);
}
.seg__item--expense { --seg-tint: var(--up); }
.seg__item--income { --seg-tint: var(--accent); }
.seg__item.is-active.seg__item--income { color: var(--accent-ink); }
.seg__item--transfer { --seg-tint: #4fa3f7; }

.amount {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  padding: 10px 0 2px;
}
.amount__value {
  font-size: 38px;
  font-weight: 700;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.amount__value.is-empty { color: var(--hint); }
.amount__currency { color: var(--hint); font-size: 15px; }

.amount__note {
  min-height: 18px;
  display: flex;
  justify-content: center;
}
/* The error wins the line: a hint about the limit next to «enter an amount» is noise. */
.amount__error:not(:empty) + .amount__limit { display: none; }
.amount__limit {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--hint);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.amount__limit.is-over { color: var(--warm); }
.amount__limitbar {
  position: relative;
  flex-shrink: 0;
  width: 56px; height: 5px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--line);
}
.amount__limitwas,
.amount__limitnow {
  position: absolute;
  top: 0; bottom: 0; left: 0;
}
.amount__limitwas { background: color-mix(in srgb, var(--accent) 40%, transparent); }
.amount__limitnow {
  background: var(--accent);
  transition: left .2s ease, width .2s ease;
}
.amount__limit.is-over .amount__limitnow { background: var(--warm); }
.amount__error {
  text-align: center;
  color: var(--up);
  font-size: 13px;
}

.cats {
  display: flex;
  gap: 10px;
  padding: 6px 16px 4px;
  margin: 0 -16px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  touch-action: pan-x pan-y;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.cats::-webkit-scrollbar { display: none; }

.cat {
  flex: 0 0 auto;
  width: 58px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  color: var(--hint);
  font-size: 11px;
}
.cat__icon {
  width: 42px; height: 42px;
  transition: transform .12s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid transparent;
  /* A rounded square, not a circle: the same shape as the keys, the fields and the
     feed's icons — one family of forms on the screen instead of circles among tiles. */
  border-radius: var(--r-field);
  background: var(--bg);
  font-size: 20px;
}
.cat__name {
  max-width: 58px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The chosen category: filled with its own colour plus the name in full contrast. A ring
   alone is not enough — against a dark background the choice was lost. */
.cat.is-active .cat__icon { transform: scale(1.04); }
.cat.is-active .cat__name { color: var(--text); font-weight: 600; }
.cat:active { opacity: .6; }

/* The description under the amount: a field of the same family as the keys. */
.editor__desc { margin: 10px 0 2px; }

/* The details bar: the date, the account, the tags and «⋯» as equal cells of one
   rounded bar — nothing scrolls away, and the shape repeats the keypad below. */
.details {
  display: flex;
  height: 44px;
  margin: 2px 0 12px;
  border-radius: var(--r-field);
  background: var(--bg);
  overflow: hidden;
}
.details__cell {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  padding: 0 14px;
  color: var(--text);
  font-size: 14px;
  font-weight: 500;
}
.details__cell + .details__cell { box-shadow: inset 1px 0 0 var(--line); }
.details__cell svg { flex: 0 0 auto; color: var(--hint); }
.details__cell.is-active, .details__cell.is-active svg { color: var(--accent); }
.details__cell:active { opacity: .6; }
.details__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* «More» is only its dots: a square cell the height of the bar. */
.details__cell[data-chip="more"] { width: 48px; padding: 0; }
/* The names grow into the free width and, when it runs out, give way in proportion
   to their length — the long one loses most. */
.details__cell--name { flex: 1 1 auto; min-width: 0; padding: 0 10px; }
/* A required cell left empty — a short shake, since the bar does not scroll to it. */
.details__cell.is-missing { animation: missing .36s ease; color: var(--up); }
@keyframes missing {
  20%, 60% { transform: translateX(-3px); }
  40%, 80% { transform: translateX(3px); }
}

/* Where the description led the category. A quiet line when it chose on its own, a
   tappable plaque when the person's own choice differs from their habit. */
.cat-hint {
  padding: 0 4px 8px;
  text-align: center;
  color: var(--hint);
  font-size: 13px;
}
.cat-hint__take {
  padding: 7px 12px;
  border-radius: var(--r-inner);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
  font-size: 13px;
  font-weight: 500;
}
.cat-hint__take:active { opacity: .6; }

.cat__icon--more { border-color: var(--line); color: var(--hint); }
/* «New category» in the catalogue makes the same promise as «New account» on the accounts
   screen: an accented dashed border means «this is where new things are created». */
.cat__icon--add {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--accent);
}

/* the number pad: ✓ stands on the right at full height — a large target for a thumb */
.pad {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 7px;
  margin-top: 8px;
}
.pad__key {
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-field);
  background: var(--bg);
  font-size: 22px;
  font-weight: 500;
}
.pad__key:active { opacity: .55; }
.pad__zero { grid-column: span 2; }
.pad__ok {
  grid-column: 4;
  grid-row: 2 / span 3;
  height: auto;
  background: var(--accent-face);
  color: var(--on-accent);
  font-size: 26px;
}

/* the «Another date» row: the system calendar lies over it as a transparent layer */
.sheet__row--picker { position: relative; }
.sheet__date {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  border: 0;
  background: none;
}

.sheet__note {
  padding: 2px 4px 14px;
  text-align: center;
  color: var(--hint);
  font-size: 15px;
}
/* The key is reaching into other shops — that has to read as an alarm, not as a note. */
.sheet__note.is-warn { color: var(--up); }

/* The submit button is sometimes narrow (next to a search field) and sometimes full width
   (in forms) — the place decides the width, not the button itself. */
.sheet__submit--wide { width: 100%; }
.sheet__submit--danger { width: 100%; background: var(--up); color: #fff; }

/* The «clear the choice» button at the bottom of a sheet. A plaque rather than bare text:
   without a surface behind it, it read as a caption under the list and nobody thought of
   pressing it. */
.sheet__cancel {
  width: 100%;
  margin-top: 8px;
  padding: 13px;
  border-radius: var(--r-card);
  background: var(--bg);
  color: var(--hint);
  font-size: 16px;
}
.sheet__cancel:active { opacity: .6; }

/* the full list of categories — a grid four across, as in the sorting */
.catgrid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px 8px;
  padding: 8px 0 16px;
}
/* min-width: 0 is mandatory: without it a long name («Public transport») widens the column
   and the grid runs off the edge of the screen instead of wrapping. */
.catgrid .cat { width: auto; min-width: 0; }
.catgrid .cat__name { width: 100%; max-width: 100%; text-align: center; }
/* «Nothing found» is not a grid cell: without this it was squeezed into a column a quarter
   of the screen wide and wrapped one word at a time. */
.catgrid .feed__note { grid-column: 1 / -1; }

/* At a computer: the keypad gives way to the keyboard. A caret after the figure shows
   that the digits go there; it hides while a text field has the focus. */
.pad .editor__save { grid-column: 1 / -1; margin-top: 4px; }
.amount { cursor: default; }
.amount.is-live .amount__value::after {
  content: "";
  display: inline-block;
  width: 2px;
  height: .8em;
  margin-left: 3px;
  vertical-align: -0.05em;
  background: var(--accent);
  animation: caret 1.1s steps(1) infinite;
}
@keyframes caret { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .amount.is-live .amount__value::after { animation: none; }
}
