/* The operations feed, the safety net on «Analytics», rows with a hidden action, a day's card.
   One of the stylesheets index.html loads IN ORDER: a rule here may rely on coming
   after the files before it. */

/* --- the operations feed --- */
.feed { padding: 0 16px; transition: opacity .12s ease; }
/* The previous filter's rows, waiting for the new answer — dimmed, never blank. */
.feed.is-stale { opacity: .4; pointer-events: none; }

.feed__day {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 4px 10px;
  font-size: 13px;
  color: var(--hint);
  font-variant-numeric: tabular-nums;
}

/* A day's name starts with a capital, as a heading does: «Сегодня», «Вторник, 22 сентября». */
.feed__day > span:first-child { display: inline-block; }
.feed__day > span:first-child::first-letter { text-transform: uppercase; }
/* A category's operations in a sheet over the summary: the sheet already has its margins. */
.sheetlist .feed { padding: 0; }
.sheetlist .feed__day:first-child { padding-top: 4px; }

/* What came in that day stands beside what went out, in the accent — never folded into
   one number: «spent + earned» is a sum of nothing. Plain text, not a plate: a tinted
   plate is how a chip looks, and this is not something to tap. */
.feed__daysums { display: inline-flex; align-items: center; gap: 10px; }
.feed__dayin {
  color: var(--accent-ink);
  font-weight: 600;
}

.op {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 13px 14px;
  border-radius: var(--r-card);
  background: var(--surface);
  box-shadow: var(--edge), var(--lift);
  text-align: left;
}
/* The rows breathe: a list stuck together reads as a table rather than as cards. Neighbours
   come in two kinds — a bare row and a row in a swipe wrapper (`.swipe`) — and the gap is
   needed between ANY pair. While the rules covered matching pairs only, the «All
   operations» feed stuck together around the transfers: they alone are not wrapped, and in
   a run of expenses they broke the chain. */
.op + .op,
.op + .swipe,
.swipe + .op { margin-top: 8px; }
.op:active { opacity: .6; }

.op__icon {
  position: relative;
  flex: 0 0 auto;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: var(--r-inner);
  /* --cat is set by the row: the colour of the operation's category. A filled square
     without a ring — one family with the keys and the «+», and a ring around an emoji
     was a frame around a picture. Without a category the square is a neutral grey. */
  background: color-mix(in srgb, var(--cat, var(--hint)) 18%, transparent);
  font-size: 17px;
}

.op__text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 15px;
}

.op__sum {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.op__sum.is-income { color: var(--accent-ink); }
/* Money that came back is not money earned, and a purchase that came back in
   full did not cost anything. Both keep their real figure — the bank did move
   it — but neither gets the accent colour that says «this is your month». */
.op__sum.is-void { color: var(--hint); font-weight: 500; }
.op__sum.is-struck { text-decoration: line-through; }

/* A small label before the description: «Refund», «300 came back». */
.op__tag {
  display: inline-block;
  margin-right: 6px;
  padding: 1px 6px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--hint) 16%, transparent);
  color: var(--hint);
  font-size: 11px;
  font-weight: 600;
  vertical-align: 1px;
}
/* A tag's mark: the emoji alone when it has one — the row is narrow, and the full name
   is in the card. Without the grey plaque an emoji reads as part of the description. */
.op__tag--occasion { max-width: 96px; overflow: hidden; text-overflow: ellipsis; vertical-align: bottom; }

/* The tail of «Analytics». The page's bottom padding is calculated for screens with the
   round «+» button (it floats 86px from the bottom): the feed's last row must fit
   underneath it. There is no button on the analytics screen, and the same 150px left an
   empty field one and a half times the block's own height beneath it. */
.screen--tail { margin-bottom: -46px; }

/* --- the safety net: the one block on «Analytics» that looks ahead --- */
/* A card that is itself the button (approved on the refresh board, September 2026). The
   earlier bare section read as information only: nothing said it could be tuned, and its
   settings were found by accident. Now the corner icon says «settings», and the line under
   the answer shows what the answer is made of. */
.res {
  display: block;
  width: calc(100% - 32px);
  margin: 12px 16px 0;
  padding: 14px 16px;
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--edge), var(--lift);
  text-align: left;
  color: var(--text);
}
.res:empty { display: none; }
.res:active { opacity: .7; }
.res__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.res__title { font-size: 13px; color: var(--hint); }
.res__tune {
  width: 30px; height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  background: color-mix(in srgb, var(--text) 7%, transparent);
  color: var(--text);
}
.res__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-top: 6px;
}
.res__answer {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
/* Nothing to count is a message rather than a number: it should look like a line of text,
   or it reads as the answer «there is no money». */
.res__head--empty .res__answer { font-size: 15px; font-weight: 500; color: var(--hint); }
/* The cushion's scale: 0–3, 3–6 and 6–12 months, one track in three stretches. */
.res__scale { margin-top: 12px; }
.res__track,
.res__marks {
  display: grid;
  grid-template-columns: 1fr 1fr 2fr;
  gap: 3px;
}
.res__seg {
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(to right, var(--accent) var(--fill, 0%), var(--line) var(--fill, 0%));
}
.res__marks { margin-top: 5px; }
.res__mark { text-align: right; font-size: 11px; color: var(--hint); }
.res__mark.is-reached { color: var(--accent-ink); font-weight: 600; }
.res__formula {
  margin-top: 8px;
  font-size: 13px;
  color: var(--hint);
  font-variant-numeric: tabular-nums;
}
.res__formula b { color: var(--text); font-weight: 600; }

/* The safety net's sheet: the answer on top follows every switch below it. */
.tune__answer { padding: 6px 0 4px; text-align: center; }
.tune__months {
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.tune__sum { margin-top: 2px; font-size: 13px; color: var(--hint); font-variant-numeric: tabular-nums; }
.tune__tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.tune__tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 11px 10px;
  border-radius: 16px;
  background: var(--bg);
  color: var(--text);
  text-align: left;
}
.tune__tile.is-current {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface));
  box-shadow: inset 0 0 0 2px var(--accent);
}
.tune__label { font-size: 13px; font-weight: 600; }
.tune__figure { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
.tune__list {
  overflow: hidden;
  border-radius: 18px;
  background: var(--bg);
}
.tune__acc {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  text-align: left;
  color: var(--text);
}
.tune__acc + .tune__acc { box-shadow: inset 0 1px 0 var(--line); }
.tune__acc .op__icon { background: var(--surface); }
.tune__acctext { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.tune__accname { font-size: 15px; font-weight: 500; }
.tune__accsum { font-size: 13px; color: var(--hint); font-variant-numeric: tabular-nums; }
.tune__box {
  flex-shrink: 0;
  width: 26px; height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  box-shadow: inset 0 0 0 2px var(--line);
  color: transparent;
  font-size: 11px;
  font-weight: 600;
}
.tune__acc.is-on .tune__box {
  background: var(--accent);
  box-shadow: none;
  color: var(--on-accent);
}
/* Another currency: visible, so nothing looks lost, and plainly out of reach. */
.tune__acc.is-other { opacity: .4; }
.tune__list.is-other .tune__acc.is-other { opacity: 1; }   /* the group is dimmed already */
.tune__acc.is-other .tune__box { width: auto; box-shadow: none; color: var(--hint); }

/* --- a row with a hidden action area --- */
/* The row is not a card with buttons glued to its side: it is a card lying on a
   recess. The wrapper IS that recess — one dark plate the size of the row, with
   the same corners — and the actions are printed straight onto it, no plates of
   their own, no seam between them. Sliding the card aside uncovers it.
   `pan-y` leaves the vertical scroll to the browser and hands us the sideways
   drag — without it the list would fight the gesture. */
.swipe {
  position: relative;
  border-radius: var(--r-card);
  overflow: hidden;
  touch-action: pan-y;
  /* The recess is tinted with the accent: the actions under the card belong to the app,
     not to a black hole in the list. */
  background: color-mix(in srgb, var(--accent) 16%, var(--bg));
  box-shadow: var(--lift);
}
.swipe + .swipe { margin-top: 8px; }
.swipe .op { position: relative; }
/* will-change lifts the row into a layer of its own, and that layer is composited ON TOP of
   the group already assembled: while the list was filling in, the buttons underneath showed
   through the half-transparent row. The layer is needed for exactly as long as the drag —
   kept permanently it speeds nothing up and shows what should not be seen. */
.swipe.is-dragging .op { will-change: transform; }
/* Lifted off the recess while it is open: the shadow along the card's own edge
   is what makes the gap read as depth rather than as a cut. */
.swipe.is-open .op {
  box-shadow: var(--edge), -14px 0 22px -10px rgba(0, 0, 0, .55);
}

.swipe__tray {
  position: absolute;
  inset: 0 0 0 auto;
  display: flex;
}
/* The card over the recess is never see-through. A row dims under the finger
   everywhere else (`.op:active`), and a dimmed card here showed the tray THROUGH
   itself: a light tap looked like two buttons surfacing on top of the operation.
   The recess must be uncovered by the slide and by nothing else, so the press
   changes the card's own colour instead — it hides exactly as well as the card. */
.swipe .op:active {
  opacity: 1;
  background: color-mix(in srgb, var(--text) 7%, var(--surface));
}

.swipe__act {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  color: var(--accent-ink);
}
.swipe__act.is-danger { color: var(--up); }
.swipe__act:active { opacity: .55; }
/* A full swipe with one action (the summary's categories). The recess is not the accent:
   taking a category out of the ring is fading it, so the recess is a quiet grey; bringing
   it back tints it with the accent (`--recess`, set per row). */
.swipe--commit {
  --recess: var(--hint);
  background: color-mix(in srgb, var(--recess) 24%, var(--bg));
  transition: background .16s ease;
}
.swipe--commit.is-armed { background: color-mix(in srgb, var(--recess) 42%, var(--bg)); }
.swipe__mark {
  position: absolute;
  top: 50%;
  right: 22px;
  margin-top: -10.5px;
  display: flex;
  color: color-mix(in srgb, var(--recess) 55%, var(--text));
  opacity: 0;
  pointer-events: none;
}
.swipe__mark svg { transition: transform .18s cubic-bezier(.3, 1.6, .5, 1); }
.swipe--commit.is-armed .swipe__mark svg { transform: scale(1.22); }
/* Out of the ring: the row stays, readable but clearly aside. Only its contents fade —
   the card itself stays solid, or the recess would show through it. */
.op.is-muted > * { opacity: .4; }
.op.is-muted .op__icon { filter: grayscale(1); }
.swipe--commit .op > * { transition: opacity .3s ease, filter .3s ease; }
@media (prefers-reduced-motion: reduce) {
  .swipe--commit .op > *, .swipe__mark svg { transition: none; }
}
/* A deleted row folds away while its undo strip is up. */
.swipe.is-gone {
  opacity: 0;
  transition: height .22s ease, opacity .16s ease;
}
@media (prefers-reduced-motion: reduce) {
  .swipe.is-gone { transition: none; }
}

.feed__note {
  padding: 40px 16px;
  text-align: center;
  color: var(--hint);
  font-size: 14px;
}

.feed__sentinel { height: 1px; }

/* --- a day's operations share one card --- */
/* Every row its own floating card made the feed a pile of equal bricks: four rows a
   screen, nothing to rest the eye on. One card per day, rows divided by a hairline — the
   day reads as a whole and twice as much fits. */
.feed__group {
  position: relative;
  overflow: hidden;
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--lift);
}
/* The card's hairline is drawn OVER its rows. As an inset shadow of the group itself it
   lay under them — every row's own background covered it, and a day, the limits and the
   accounts came out flat next to the outlined cards around them. */
.feed__group::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  box-shadow: var(--edge);
  pointer-events: none;
}
.feed__group > * { position: relative; }
.feed__group.is-gone,
.feed__day.is-gone { display: none; }
.feed__group > * + *::before {
  content: "";
  position: absolute;
  z-index: 1;
  /* Edge to edge: a line starting after the icon read as cut off on the left. */
  top: 0; right: 0;
  left: 0;
  height: 1px;
  background: var(--line);
  pointer-events: none;
}
.feed__group .op,
.feed__group .swipe {
  border-radius: 0;
  box-shadow: none;
}
.feed__group .op + .op,
.feed__group .op + .swipe,
.feed__group .swipe + .op,
.feed__group .swipe + .swipe { margin-top: 0; }
/* Open on the recess, the card's edge still lifts it — but inside a day there is no
   card edge above or below to cast onto, so only the side shadow remains. */
.feed__group .swipe.is-open .op { box-shadow: -14px 0 22px -10px rgba(0, 0, 0, .45); }

/* Two lines: what it was, then only what the screen does not already say. */
.op__text .op__title,
.op__text .op__sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
}
.op__sub {
  margin-top: 1px;
  font-size: 13px;
  color: var(--hint);
}
