/* The iOS system palette, as in road-alerts. Each colour that carries meaning carries one:
   green is a row ticked off against the trader's, amber is a bag to look at, blue is the
   bag being fixed, red is deleting. None of them is ever the only sign: each comes with a
   word or a shape. */
:root {
  --bg: #F2F2F7;
  --card: #FFFFFF;
  --well: #F2F2F7;
  --sum: #E9E9EE; --sum-edge: rgba(60, 60, 67, 0.1);
  --sheet: #F2F2F7;
  --ink: #111114;
  --muted: #6B6D76;
  --faint: #A3A5AD;
  --line: #E3E3E8;
  --glass: rgba(255, 255, 255, 0.78);
  --glass-edge: rgba(255, 255, 255, 0.9);
  --shadow: 0 1px 2px rgba(16, 20, 30, 0.06), 0 10px 30px rgba(16, 20, 30, 0.1);
  --key: #FFFFFF;
  --key-down: #D5D5DB;
  --key-shadow: 0 1px 0 rgba(16, 20, 30, 0.16), 0 2px 8px rgba(16, 20, 30, 0.05);
  --blue: #007AFF;
  --red: #D92B34;
  --ok-fg: #1F7A35; --ok-bg: #E3F5E9;
  --look-fg: #9A5200; --look-bg: #FDF0DC;
  --button: #1C1C1E; --button-ink: #FFFFFF;
  --thumb: #FFFFFF;
  /* Anything arriving overshoots a touch and settles; anything sliding eases out long. */
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-ios: cubic-bezier(0.32, 0.72, 0, 1);
  /* Every number. ui-rounded is the iPhone's own rounded face; Android has none, and SF Pro
     Rounded may not ship there, so "Lua Digits" is Nunito cut to digits (digits.css). All
     its digits share one width, so a column of bags lines up. */
  --num-font: ui-rounded, "SF Pro Rounded", "Lua Digits", "Be Vietnam Pro", system-ui, sans-serif;
  --row-h: 44px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #000000; --card: #1C1C1E; --well: #2C2C2E; --sum: #333336; --sum-edge: rgba(255, 255, 255, 0.07); --sheet: #121214; --ink: #FFFFFF; --muted: #98989D; --faint: #6C6C72; --line: #2C2C2E;
    --glass: rgba(30, 30, 32, 0.72); --glass-edge: rgba(255, 255, 255, 0.08);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.5);
    --key: #3A3A3C; --key-down: #5C5C60; --key-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
    --blue: #0A84FF; --red: #FF453A;
    --ok-fg: #30D158; --ok-bg: rgba(48, 209, 88, 0.16);
    --look-fg: #FF9F0A; --look-bg: rgba(255, 159, 10, 0.18);
    --button: #FFFFFF; --button-ink: #000000;
    --thumb: #636366;
  }
}
:root[data-theme="dark"] {
  --bg: #000000; --card: #1C1C1E; --well: #2C2C2E; --sum: #333336; --sum-edge: rgba(255, 255, 255, 0.07); --sheet: #121214; --ink: #FFFFFF; --muted: #98989D; --faint: #6C6C72; --line: #2C2C2E;
  --glass: rgba(30, 30, 32, 0.72); --glass-edge: rgba(255, 255, 255, 0.08);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.5);
  --key: #3A3A3C; --key-down: #5C5C60; --key-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
  --blue: #0A84FF; --red: #FF453A;
  --ok-fg: #30D158; --ok-bg: rgba(48, 209, 88, 0.16);
  --look-fg: #FF9F0A; --look-bg: rgba(255, 159, 10, 0.18);
  --button: #FFFFFF; --button-ink: #000000;
  --thumb: #636366;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; }
body {
  background: var(--bg); color: var(--ink);
  font-family: 'Be Vietnam Pro', system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  transition: background-color 0.6s ease, color 0.6s ease;
}
[hidden] { display: none !important; }
button { font: inherit; color: inherit; cursor: pointer; margin: 0; }
button:disabled { cursor: default; }
input { font: inherit; color: inherit; -webkit-user-select: text; user-select: text; }

/* The whole screen fits the phone: header, notebook, the slot, the keypad. Only the
   notebook scrolls. */
.app {
  height: 100vh; height: 100dvh;
  display: flex; flex-direction: column;
  padding-top: env(safe-area-inset-top);
  background: var(--bg);
  transform-origin: 50% 0;
  transition: transform 0.55s var(--ease-ios), border-radius 0.55s var(--ease-ios), filter 0.55s ease, background-color 0.6s ease;
}
/* A card over the weighing screen, as iOS presents one: the screen behind steps back and
   darkens, so it is plain the keypad is still there underneath. */
body.behind { background: #000; }
body.behind .app {
  transform: translateY(calc(env(safe-area-inset-top) + 8px)) scale(0.92);
  border-radius: 24px; overflow: hidden; filter: brightness(0.8);
}

/* ---------- header: the sale, and its total rolling up ---------- */

/* The sale at the top is the way into its money: tapping it opens the card. */
.top {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
  padding: 12px 18px 10px; cursor: pointer; outline: none;
  transition: transform 0.25s var(--spring), opacity 0.2s ease;
}
.top:active, .top.down { transform: scale(0.98); opacity: 0.75; }
.sale { min-width: 0; }
.sale-name { display: flex; align-items: center; gap: 2px; font-size: clamp(18px, 5.8vw, 21px); font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; white-space: nowrap; }
.sale-name span { overflow: hidden; text-overflow: ellipsis; }
.sale-name .chev { flex: none; color: var(--faint); margin-top: 1px; }
.sale-meta { margin-top: 2px; font-size: 13px; font-weight: 500; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.grand { flex: none; text-align: right; }
.grand-kg { display: flex; align-items: baseline; justify-content: flex-end; font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: clamp(26px, 8.6vw, 32px); font-weight: 800; letter-spacing: -0.02em; line-height: 1; }
.grand-kg .unit { margin-left: 4px; font-size: 15px; font-weight: 700; color: var(--muted); letter-spacing: 0; }
.grand-count { margin-top: 3px; font-family: var(--num-font); font-size: 13px; font-weight: 600; color: var(--muted); }

/* The reels. Each digit is a strip of 0 to 9 behind a window one digit tall. */
.reels { display: inline-flex; }
.rl {
  display: inline-block; height: 1.1em; line-height: 1.1em; overflow: hidden;
  -webkit-mask-image: linear-gradient(transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(transparent, #000 18%, #000 82%, transparent);
}
.rl-strip { display: flex; flex-direction: column; transition: transform 0.6s var(--ease-ios); }
.rl-strip i { font-style: normal; height: 1.1em; text-align: center; }
.rs { display: inline-block; line-height: 1.1em; }
.rl.in, .rs.in { animation: reel-in 0.45s var(--spring) both; }
@keyframes reel-in { from { transform: translateY(-35%); opacity: 0; } }

.unsaved {
  margin: 0 12px 8px; padding: 9px 14px; border-radius: 14px;
  background: var(--look-bg); color: var(--look-fg); font-size: 13.5px; font-weight: 700;
}

/* ---------- the notebook ---------- */

.paper { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
.book {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 6px 12px 12px;
  scrollbar-width: none;
  /* Rows scrolled up fade out under the header instead of being cut on a hard line. */
  -webkit-mask-image: linear-gradient(transparent, #000 10px);
  mask-image: linear-gradient(transparent, #000 10px);
}
.book::-webkit-scrollbar { display: none; }
.rows { background: var(--card); border-radius: 22px; box-shadow: var(--shadow); padding: 4px 8px; transition: background-color 0.6s ease; }

/* Five bags across and their sum at the end, so a row reads in one glance and compares
   with a row of the trader's notebook. */
.row {
  display: grid; grid-template-columns: 24px repeat(5, minmax(0, 1fr)) 78px; align-items: center; gap: 3px;
  height: var(--row-h); border-bottom: 0.5px solid var(--line);
  /* A thousand bags is two hundred rows, and a cheap phone should only lay out the few on
     screen. Every row is the same height, so the estimate is exact. */
  content-visibility: auto; contain-intrinsic-size: auto var(--row-h);
}
.row:last-child { border-bottom: 0; }
.row.enter { animation: row-in 0.36s var(--ease-ios) both; overflow: hidden; }
.row.exit { animation: row-out 0.24s var(--ease-ios) both; overflow: hidden; }
@keyframes row-in { from { height: 0; opacity: 0; } }
@keyframes row-out { to { height: 0; opacity: 0; } }

.rn { font-family: var(--num-font); font-size: 11.5px; font-weight: 600; color: var(--faint); padding-left: 2px; }

.c, .s {
  height: 34px; border: 0; border-radius: 10px; padding: 0; background: transparent;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: clamp(15px, 4.3vw, 18px); line-height: 1;
  position: relative; white-space: nowrap;
  transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.25s ease, transform 0.25s var(--spring);
}
.c { font-weight: 600; }
.c.down, .s:active { transform: scale(0.94); }
/* Where the next bag will land. */
.c.next::after {
  content: ''; position: absolute; inset: 3px; border-radius: 8px;
  border: 1.5px dashed var(--faint); animation: seat 1.6s ease-in-out infinite;
}
@keyframes seat { 50% { opacity: 0.35; } }
.c.last { background: var(--well); }
/* Hidden at once, not faded: the number is still in the air on its way here. */
.c.incoming { color: transparent; transition: none; }
.c.land { animation: land 0.42s var(--spring) both; }
@keyframes land { from { transform: scale(0.55); opacity: 0; } }
.c.leave { animation: leave 0.22s ease both; }
@keyframes leave { to { transform: scale(0.5) translateY(8px); opacity: 0; } }
.c.flip { animation: flip 0.5s var(--ease-ios) both; }
@keyframes flip { from { transform: perspective(200px) rotateX(85deg); opacity: 0.2; } }
/* A bag to look at: amber with a question mark, never colour alone. */
.c.flag { background: var(--look-bg); color: var(--look-fg); font-weight: 700; }
.c.flag::before {
  content: '?'; position: absolute; top: -4px; right: -3px; width: 15px; height: 15px; border-radius: 50%;
  background: var(--look-fg); color: var(--card);
  font: 800 10px/15px 'Be Vietnam Pro', system-ui, sans-serif; text-align: center;
  animation: badge 0.45s var(--spring) both;
}
@keyframes badge { from { transform: scale(0); } }
.c.sel { box-shadow: 0 0 0 2px var(--blue); background: var(--card); color: var(--ink); }

/* Wide enough for 500,0 and its ring at 18px; the bags beside it give up 2px each. */
.s { font-weight: 800; gap: 5px; }
/* The row's sum, read out against the trader's notebook. Its own fill, firmer than the last
   bag's, and a hairline edge, so the column holds in hard sun, where --well on white all but
   vanishes. Neutral until checked: a row not yet compared is not a fault, and the trader
   can see the screen. */
.s:not(:empty) { background: var(--sum); box-shadow: inset 0 0 0 1px var(--sum-edge); }
.s:empty::after { content: ''; width: 14px; height: 2px; border-radius: 1px; background: var(--line); }
.s.drop { animation: drop 0.55s var(--spring) both; }
@keyframes drop { from { transform: translateY(-16px) scale(0.7); opacity: 0; } }
.s.bump { animation: bump 0.45s var(--spring); }
@keyframes bump { 40% { transform: scale(1.12); } }
.s.ok { background: var(--ok-bg); color: var(--ok-fg); box-shadow: inset 0 0 0 1px transparent; }
/* The sum panel's tick circle, smaller. An empty ring on every closed row says it can be
   ticked, and holds the tick's place, so the number never shifts when the tick arrives.
   Checked, the ring fills and the tick draws itself in; unchecked, both run back. */
.s .ring {
  flex: none; width: 14px; height: 14px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1.5px solid var(--faint); color: transparent;
  transition: background-color 0.3s ease, border-color 0.3s ease, color 0.15s ease;
}
.s .ring .tk { width: 10px; height: 10px; stroke-width: 4; }
.s .ring .tk path { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 0.28s var(--ease-ios); }
.s.ok .ring { background: var(--ok-fg); border-color: var(--ok-fg); color: var(--card); }
.s.ok .ring .tk path { stroke-dashoffset: 0; transition-delay: 0.08s; }
.ring.pop { animation: stamp-btn 0.45s var(--spring); }

/* The number in the air between the slot and its seat. */
.ghost {
  position: fixed; left: 0; top: 0; z-index: 30; pointer-events: none;
  font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: clamp(15px, 4.3vw, 18px); font-weight: 700; line-height: 1;
  color: var(--ink); transform-origin: center; will-change: transform; white-space: nowrap;
}

/* The first launch: one line on the only rule there is, and the demo. */
.hint { padding: 20px 16px 8px; text-align: center; color: var(--muted); font-size: 14.5px; font-weight: 500; }
.hint p { margin: 0 0 10px; }
.hint-eg { display: flex; align-items: center; justify-content: center; gap: 5px; }
.hint-eg .kc {
  display: inline-grid; place-items: center; width: 30px; height: 36px; border-radius: 9px;
  background: var(--key); box-shadow: var(--key-shadow); color: var(--ink);
  font-family: var(--num-font); font-size: 19px; font-weight: 600;
}
.hint-eg .arrow { margin: 0 6px; color: var(--faint); }
.hint-eg b { font-family: var(--num-font); font-size: 24px; font-weight: 800; color: var(--ink); margin-right: 2px; }
.hint-demo {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 8px; padding: 11px 18px; border: 0; border-radius: 999px;
  background: var(--card); box-shadow: var(--shadow); color: var(--ink); font-size: 15px; font-weight: 700; text-decoration: none;
  transition: transform 0.25s var(--spring);
}
.hint-demo:active { transform: scale(0.97); }
/* Second to the demo, so quieter: no card, and on its own line under it. */
.hint-install { display: flex; width: fit-content; margin: 4px auto 0; background: transparent; box-shadow: none; color: var(--muted); }
/* Chrome's offer comes a moment after the page, so the button arrives rather than appears. */
.hint-install.in, .fin-btn.in { animation: offer-in 0.5s var(--spring) both; }
@keyframes offer-in { from { opacity: 0; transform: translateY(6px) scale(0.92); } }
.hint.gone { animation: hint-out 0.3s var(--ease-ios) both; }
@keyframes hint-out { to { opacity: 0; transform: translateY(10px); } }

/* ---------- the slot ---------- */

.entry {
  display: flex; margin: 0 12px 10px; min-height: 88px;
  background: var(--card); border-radius: 22px; box-shadow: var(--shadow); overflow: hidden;
  transition: background-color 0.6s ease;
}
.last { flex: 0 0 44%; min-width: 0; padding: 12px 10px 12px 16px; border-right: 0.5px solid var(--line); display: flex; align-items: center; cursor: pointer; }
.last > .in { width: 100%; animation: swap-in 0.42s var(--spring) both; }
@keyframes swap-in { from { transform: translateY(12px); opacity: 0; filter: blur(3px); } }
.last .lb { display: flex; align-items: center; gap: 6px; min-height: 22px; font-size: 12.5px; font-weight: 600; color: var(--muted); white-space: nowrap; }
.last .lb > span:first-child { overflow: hidden; text-overflow: ellipsis; }
.last .v { margin-top: 3px; font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: clamp(24px, 8vw, 30px); font-weight: 800; letter-spacing: -0.02em; line-height: 1; }
.last .v small { margin-left: 3px; font-size: 14px; font-weight: 700; color: var(--muted); letter-spacing: 0; }
.last .quiet .v { color: var(--faint); }
.last .look .v { color: var(--look-fg); }
.tag { flex: none; padding: 2px 8px; border-radius: 999px; background: var(--look-bg); color: var(--look-fg); font-size: 11.5px; font-weight: 700; }
.sumline { display: flex; align-items: center; gap: 6px; margin-top: 3px; }
.sumline .v { margin-top: 0; }
.sumcard .lb { transition: color 0.3s ease; }
.sumcard.on .lb { color: var(--ok-fg); }
.okbtn {
  flex: none; margin-left: auto; width: 30px; height: 30px; padding: 0; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid var(--faint); background: transparent; color: transparent;
  transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease, transform 0.25s var(--spring);
}
.okbtn .tk { width: 16px; height: 16px; }
.sumcard:active .okbtn, .okbtn.down { transform: scale(0.9); }
.sumcard.on .okbtn { background: var(--ok-fg); border-color: var(--ok-fg); color: var(--card); }
.okbtn.stamp { animation: stamp-btn 0.45s var(--spring); }
@keyframes stamp-btn { 40% { transform: scale(1.22); } }

.now { flex: 1; min-width: 0; padding: 10px 12px 12px 14px; display: flex; flex-direction: column; justify-content: center; gap: 6px; }
.slot-label { font-size: 12.5px; font-weight: 600; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.slot { display: flex; align-items: flex-end; gap: 5px; }
/* The boxes give way on a narrow phone rather than pushing the slot out of its card. */
.slot .d {
  position: relative; flex: 1 1 0; min-width: 0; max-width: 40px; height: 50px; border-radius: 12px; background: var(--well);
  display: grid; place-items: center;
  font-family: var(--num-font); font-size: 32px; font-weight: 700; line-height: 1;
  transition: box-shadow 0.2s ease, background-color 0.2s ease;
}
.slot .d.next { box-shadow: inset 0 0 0 2px var(--ink); background: var(--card); }
.slot .d.next::after {
  content: ''; width: 2px; height: 26px; border-radius: 1px; background: var(--ink);
  animation: caret 1.1s steps(1) infinite;
}
@keyframes caret { 50% { opacity: 0; } }
.slot .dg { animation: digit 0.32s var(--spring) both; }
@keyframes digit { from { transform: translateY(10px) scale(0.6); opacity: 0; } }
.slot .comma { font-family: var(--num-font); font-size: 32px; font-weight: 800; line-height: 1; color: var(--muted); margin: 0 -1px 2px; }
.slot .u { margin: 0 0 5px 3px; font-size: 14px; font-weight: 700; color: var(--muted); }
.slot.shake { animation: shake 0.42s ease; }
@keyframes shake { 20% { transform: translateX(-7px); } 40% { transform: translateX(6px); } 60% { transform: translateX(-4px); } 80% { transform: translateX(2px); } }

/* ---------- the keypad ---------- */

.keypad {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px;
  padding: 0 12px calc(10px + env(safe-area-inset-bottom));
}
.key {
  height: clamp(48px, 7.2vh, 60px); border: 0; border-radius: 14px; padding: 0; white-space: nowrap;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--key); box-shadow: var(--key-shadow); color: var(--ink);
  font-family: var(--num-font); font-size: 27px; font-weight: 600; line-height: 1;
  touch-action: manipulation;
  transition: transform 0.28s var(--spring), background-color 0.28s ease;
}
/* Pressed: in fast, out on the spring. */
.key.down { transform: scale(0.97); background: var(--key-down); transition-duration: 0.06s; }
.key.fn { background: transparent; box-shadow: none; font-family: inherit; font-size: 14.5px; font-weight: 600; }
.key.fn.down { background: var(--key-down); }

/* ---------- toast and the demo trader's voice ---------- */

.toast {
  position: absolute; left: 50%; bottom: 14px; z-index: 10; transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px; max-width: calc(100% - 24px);
  padding: 7px 7px 7px 16px; border-radius: 999px;
  background: rgba(28, 28, 30, 0.9); color: #fff; font-size: 14px; font-weight: 600; white-space: nowrap;
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.5);
}
.toast span { overflow: hidden; text-overflow: ellipsis; }
.toast button { flex: none; border: 0; border-radius: 999px; padding: 7px 13px; background: rgba(255, 255, 255, 0.18); color: #fff; font-weight: 700; font-size: 14px; }
.toast.in { animation: pill-in 0.4s var(--spring) both; }
@keyframes pill-in { from { transform: translateX(-50%) translateY(10px) scale(0.9); opacity: 0; } }

.call {
  position: absolute; left: 50%; top: 10px; z-index: 6; transform: translateX(-50%);
  display: flex; align-items: center; gap: 9px; padding: 9px 18px 9px 13px; border-radius: 999px;
  background: rgba(28, 28, 30, 0.88); color: #fff; font-size: 17px; font-weight: 700; white-space: nowrap;
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.5); pointer-events: none;
}
.call.in { animation: call-in 0.42s var(--spring) both; }
.call.out { animation: call-out 0.3s ease both; }
@keyframes call-in { from { transform: translateX(-50%) translateY(-10px) scale(0.85); opacity: 0; } }
@keyframes call-out { to { transform: translateX(-50%) translateY(-6px) scale(0.95); opacity: 0; } }

.demo-bar {
  display: flex; align-items: center; gap: 10px; margin: 8px 12px 0; padding: 5px 5px 5px 14px; border-radius: 999px;
  background: var(--glass); border: 0.5px solid var(--glass-edge); box-shadow: var(--shadow);
  -webkit-backdrop-filter: blur(24px) saturate(180%); backdrop-filter: blur(24px) saturate(180%);
}
.demo-bar:not([hidden]) { animation: swap-in 0.5s var(--spring) both; }
.db-label { flex: none; white-space: nowrap; font-size: 11.5px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); }
.db-note { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.db-btn { flex: none; border: 0; border-radius: 999px; padding: 7px 13px; background: var(--well); font-size: 13.5px; font-weight: 700; transition: transform 0.25s var(--spring), background-color 0.25s ease, color 0.25s ease; }
.db-btn:active { transform: scale(0.94); }
.db-btn.on, .db-btn.db-start { background: var(--button); color: var(--button-ink); }
.db-start:not([hidden]) { animation: breathe 2.2s ease-in-out infinite; }
/* Silent until tapped: the button says so in words and breathes. Once on, just the icon. */
.db-sound { display: inline-flex; align-items: center; gap: 5px; }
.db-sound:not(.on):not([hidden]) { background: var(--button); color: var(--button-ink); animation: breathe 2.2s ease-in-out infinite; }
.db-sound.on { padding: 7px 9px; }
.db-sound .snd-on, .db-sound.on .snd-off { display: none; }
.db-sound.on .snd-on { display: block; }
.db-sound span:empty { display: none; }
@keyframes breathe { 50% { transform: scale(1.05); } }
.db-x { flex: none; width: 32px; height: 32px; border: 0; border-radius: 50%; background: var(--well); color: var(--muted); display: grid; place-items: center; }

/* ---------- the sheet for fixing a bag ---------- */

.scrim { position: fixed; inset: 0; z-index: 40; background: rgba(0, 0, 0, 0.3); opacity: 0; pointer-events: none; transition: opacity 0.4s ease; }
.scrim.on { opacity: 1; pointer-events: auto; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 41;
  padding: 0 12px calc(10px + env(safe-area-inset-bottom));
  background: var(--sheet); border-radius: 26px 26px 0 0; box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.18);
  transform: translateY(105%); transition: transform 0.5s var(--ease-ios);
  touch-action: none;
}
.sheet.on { transform: none; }
.sheet.dragging { transition: none; }
.sheet-grip { padding: 7px 0 4px; }
.grabber { width: 38px; height: 5px; border-radius: 3px; background: var(--faint); opacity: 0.5; margin: 0 auto; }
.sh-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 4px 6px 12px; }
.sh-title { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; }
.sh-sub { margin-top: 2px; font-size: 13px; font-weight: 500; color: var(--muted); }
.sh-done { flex: none; border: 0; border-radius: 999px; padding: 8px 16px; background: var(--card); font-size: 15px; font-weight: 700; color: var(--blue); }
.sh-fix { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border-radius: 20px; background: var(--card); }
.sh-fix small { display: block; margin-bottom: 5px; font-size: 12px; font-weight: 600; color: var(--muted); }
.sh-was b { font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: 30px; font-weight: 800; letter-spacing: -0.02em; }
.sh-arrow { flex: none; color: var(--faint); margin-top: 16px; }
.slot-sm .d { max-width: 36px; height: 46px; font-size: 28px; }
.sh-new { flex: 1; min-width: 0; }
.slot-sm .comma { font-size: 28px; }
.sh-flag { margin-top: 10px; padding: 10px 14px; border-radius: 14px; background: var(--look-bg); color: var(--look-fg); font-size: 13.5px; font-weight: 600; line-height: 1.4; }
.sh-actions { display: flex; gap: 8px; margin: 10px 0; }
.sh-btn {
  flex: 1; min-height: 46px; border: 0; border-radius: 14px; background: var(--card);
  display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 15px; font-weight: 700;
  transition: transform 0.25s var(--spring);
}
.sh-btn:active { transform: scale(0.97); }
.sh-btn.keep { color: var(--ok-fg); }
.sh-btn.del { color: var(--red); }
.sheet-keys { padding: 0; }

/* ---------- end of the demo ---------- */

.finish {
  position: fixed; inset: 0; z-index: 50; display: flex; align-items: flex-end;
  padding: 12px 12px calc(12px + env(safe-area-inset-bottom)); background: rgba(0, 0, 0, 0.3);
}
.finish:not([hidden]) { animation: fade-in 0.3s ease both; }
@keyframes fade-in { from { opacity: 0; } }
.fin-card {
  width: 100%; padding: 22px 20px 18px; border-radius: 28px; background: var(--card); box-shadow: var(--shadow);
  animation: sheet-up 0.55s var(--ease-ios) both;
}
@keyframes sheet-up { from { transform: translateY(110%); } }
.fin-kicker { font-size: 12px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); }
.fin-sum { margin-top: 6px; font-family: var(--num-font); font-size: 20px; font-weight: 700; color: var(--muted); }
.fin-sum b { font-size: 34px; font-weight: 800; color: var(--ink); letter-spacing: -0.02em; }
.fin-card p { margin: 10px 0 16px; font-size: 15px; line-height: 1.45; color: var(--ink); }
.fin-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.fin-btn {
  min-height: 50px; border: 0; border-radius: 16px; background: var(--well); color: var(--ink);
  display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; text-decoration: none;
  transition: transform 0.25s var(--spring);
}
.fin-btn:active { transform: scale(0.97); }
.fin-btn.wide { grid-column: 1 / -1; }
.fin-btn.primary { grid-column: 1 / -1; background: var(--button); color: var(--button-ink); font-size: 17px; }

/* ---------- the money ---------- */

.money-scrim { z-index: 44; background: rgba(0, 0, 0, 0.12); }
.money {
  position: fixed; left: 0; right: 0; bottom: 0; top: calc(env(safe-area-inset-top) + 14px); z-index: 45;
  display: flex; flex-direction: column;
  background: var(--sheet); border-radius: 28px 28px 0 0; box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.22);
  transform: translateY(105%); transition: transform 0.55s var(--ease-ios);
}
.money.on { transform: none; }
.money.dragging { transition: none; }
.mn-grip { padding: 7px 0 2px; touch-action: none; }
.mn-head { display: flex; align-items: center; justify-content: space-between; padding: 2px 16px 10px 20px; touch-action: none; }
.mn-head h2 { margin: 0; font-size: 22px; font-weight: 800; letter-spacing: -0.02em; }
.mn-scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 14px calc(96px + env(safe-area-inset-bottom)); }

.mn-hero { padding: 18px 20px 18px; margin-bottom: 14px; border-radius: 24px; background: var(--card); box-shadow: var(--shadow); }
.mh-label { font-size: 12.5px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); }
.mh-label.swap { animation: swap-in 0.42s var(--spring) both; }
.mh-amount {
  display: flex; align-items: baseline; margin-top: 8px;
  font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: clamp(34px, 11vw, 44px); font-weight: 800; letter-spacing: -0.02em; line-height: 1;
}
.mh-amount .unit { margin-left: 6px; font-size: 0.45em; font-weight: 700; color: var(--muted); letter-spacing: 0; }
.mh-sub { margin-top: 8px; font-size: 13.5px; font-weight: 500; color: var(--muted); }
.mh-price {
  margin-top: 10px; padding: 10px 16px; border: 0; border-radius: 999px;
  background: var(--button); color: var(--button-ink); font-size: 15px; font-weight: 700;
  transition: transform 0.25s var(--spring);
}
.mh-price:active { transform: scale(0.97); }
.mh-off, .mh-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.mh-off:not(:empty), .mh-chips:not(:empty) { margin-top: 10px; }
.mh-offchip {
  padding: 5px 11px; border-radius: 999px; background: var(--well); color: var(--muted);
  font-family: var(--num-font); font-size: 13.5px; font-weight: 700;
  animation: off-in 0.5s var(--spring) both;
}
.mh-offchip:nth-child(2) { animation-delay: 0.08s; }
@keyframes off-in { from { transform: translateY(-18px) scale(0.85); opacity: 0; } }
.mh-off.gone { animation: hint-out 0.4s var(--ease-ios) both; }
.mh-chip { padding: 5px 11px; border-radius: 999px; background: var(--well); color: var(--muted); font-size: 13px; font-weight: 600; }
.mh-chip b { font-family: var(--num-font); color: var(--ink); font-weight: 800; }
/* What is still owed is a fact, not a warning: amber belongs to bags that need a look. */
.mh-chip.strong { color: var(--ink); }

.mn-card { margin-bottom: 18px; border-radius: 20px; background: var(--card); overflow: hidden; transition: background-color 0.6s ease; }
.mn-h { margin: 22px 0 7px 16px; font-size: 12.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.mn-note { margin: -8px 16px 18px; font-size: 12.5px; color: var(--muted); }

/* The sum, a line per step. */
.st { display: flex; align-items: baseline; gap: 10px; padding: 12px 16px; border-bottom: 0.5px solid var(--line); }
.st:last-child { border-bottom: 0; }
.st-l { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 8px; }
.st-l b { flex: none; font-size: 15px; font-weight: 600; }
.st-l small { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; font-weight: 500; color: var(--muted); }
.st-v { flex: none; font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: 16px; font-weight: 700; white-space: nowrap; }
.st.sum .st-l b { font-weight: 800; }
.st.sum .st-v { font-weight: 800; }
.st.minor .st-v { color: var(--muted); font-weight: 600; }
.st.total { background: var(--ok-bg); color: var(--ok-fg); padding: 15px 16px; }
.st.total .st-l b { font-size: 16px; font-weight: 800; }
.st.total .st-v { font-size: 20px; font-weight: 800; }
.st.enter { animation: st-in 0.5s var(--spring) both; animation-delay: calc(var(--i, 0) * 45ms + 120ms); }
@keyframes st-in { from { transform: translateY(14px); opacity: 0; } }
.st-v.bump { animation: bump 0.45s var(--spring); }

/* The deal, as rows to change. */
.fr { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 8px 16px; border-bottom: 0.5px solid var(--line); }
.fr:last-child { border-bottom: 0; }
.fr.col { flex-direction: column; align-items: stretch; gap: 9px; padding: 12px 16px; }
.fr-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.fl { flex: none; font-size: 15px; font-weight: 600; }
.fnote { min-width: 0; text-align: right; font-size: 12.5px; font-weight: 500; color: var(--muted); }
.fi {
  flex: 1; min-width: 0; height: 36px; border: 0; outline: none; padding: 0; background: transparent;
  text-align: right; font-size: 16px; font-weight: 600; color: var(--ink);
}
.fi::placeholder { color: var(--faint); font-weight: 500; }
.fi.num { font-family: var(--num-font); font-variant-numeric: tabular-nums; font-size: 18px; font-weight: 700; }
.fi.left { text-align: left; }
.fi[type="date"] { font-family: var(--num-font); font-weight: 700; color-scheme: light dark; }
.fr em { flex: none; font-style: normal; font-size: 14px; font-weight: 600; color: var(--muted); }
.fr-line { display: flex; align-items: center; gap: 12px; }
.fr-line .fi { height: 34px; padding: 0 12px; border-radius: 10px; background: var(--well); }
.fr-custom { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: var(--muted); }
.fr-custom:not([hidden]) { animation: swap-in 0.4s var(--spring) both; }
.fr-custom .fi { flex: 1; height: 34px; padding: 0 10px; border-radius: 10px; background: var(--well); text-align: center; }
.fr-custom .fi.sm { flex: 0 0 64px; }

/* An iOS segmented control. The thumb slides; the labels stay put. */
.seg { position: relative; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; padding: 2px; border-radius: 10px; background: var(--well); }
.seg button {
  position: relative; z-index: 1; height: 32px; padding: 0 4px; border: 0; background: transparent;
  font-size: 13.5px; font-weight: 600; color: var(--muted); white-space: nowrap;
  transition: color 0.25s ease;
}
.seg button.on { color: var(--ink); font-weight: 700; }
.seg-thumb {
  position: absolute; left: 0; top: 2px; bottom: 2px; border-radius: 8px;
  background: var(--thumb); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 0 0 0.5px rgba(0, 0, 0, 0.04);
  transition: transform 0.4s var(--ease-ios), width 0.4s var(--ease-ios), opacity 0.2s ease;
}
.seg-sm { flex: none; width: 128px; }

.mn-actions {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: grid; grid-template-columns: 1fr 1.4fr; gap: 10px;
  padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
  background: var(--glass); border-top: 0.5px solid var(--line);
  -webkit-backdrop-filter: blur(24px) saturate(180%); backdrop-filter: blur(24px) saturate(180%);
}
.mn-btn {
  min-height: 52px; border: 0; border-radius: 16px; background: var(--card); color: var(--ink);
  font-size: 16px; font-weight: 700; box-shadow: var(--shadow);
  transition: transform 0.25s var(--spring), opacity 0.25s ease;
}
.mn-btn:active:not(:disabled), .mn-btn.down { transform: scale(0.97); }
.mn-btn.primary { background: var(--button); color: var(--button-ink); }
.mn-btn:disabled { opacity: 0.35; box-shadow: none; }

/* ---------- the phiếu ---------- */

.pv {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(12, 12, 14, 0.66);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
}
.pv:not([hidden]) { animation: fade-in 0.3s ease both; }
.pv-scroll { position: absolute; inset: 0; overflow-y: auto; overscroll-behavior: contain; padding: calc(env(safe-area-inset-top) + 64px) 16px calc(110px + env(safe-area-inset-bottom)); }
.pv-paper { position: relative; max-width: 520px; margin: 0 auto; display: flex; flex-direction: column; gap: 14px; }
.pv-page { position: relative; }
.pv-sheet { display: block; width: 100%; height: auto; border-radius: 16px; }
/* Closing the sale prints the phiếu: it rises out of the bottom like paper from a
   printer, and the stamp comes down on it. */
.pv-paper.print { animation: print 0.95s var(--ease-ios) both; }
@keyframes print { from { transform: translateY(85vh); } }
.pv-paper.rise { animation: rise 0.5s var(--ease-ios) both; }
@keyframes rise { from { transform: translateY(40px); opacity: 0; } }
.pv-stamp { position: absolute; pointer-events: none; transform: translate(-50%, -50%) rotate(var(--rot)); }
.pv-stamp.land { animation: stamp-land 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.9s both; }
@keyframes stamp-land {
  0% { opacity: 0; transform: translate(-50%, -50%) rotate(calc(var(--rot) - 14deg)) scale(2.3); }
  60% { opacity: 1; transform: translate(-50%, -50%) rotate(calc(var(--rot) + 1deg)) scale(0.94); }
  100% { opacity: 1; transform: translate(-50%, -50%) rotate(var(--rot)) scale(1); }
}
.pv-stamp.soft { animation: fade-in 0.4s ease 0.3s both; }
.pv-fx { position: absolute; width: 0; height: 0; pointer-events: none; }
.pv-fx i {
  position: absolute; left: -5px; top: -7px; width: 10px; height: 14px; border-radius: 3px;
  animation: confetti 1.35s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
@keyframes confetti {
  0% { opacity: 1; transform: translate(0, 0) rotate(0) scale(0.4); }
  55% { opacity: 1; transform: translate(var(--x), var(--y)) rotate(var(--r)) scale(1); }
  100% { opacity: 0; transform: translate(var(--x), calc(var(--y) + 140px)) rotate(calc(var(--r) * 2)) scale(1); }
}
.pv-x {
  position: absolute; top: calc(env(safe-area-inset-top) + 14px); right: 16px; z-index: 2;
  padding: 9px 18px; border: 0; border-radius: 999px;
  background: rgba(255, 255, 255, 0.16); color: #fff; font-size: 15px; font-weight: 700;
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
}
.pv-actions {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: flex; gap: 10px; padding: 12px 16px calc(14px + env(safe-area-inset-bottom));
}
.pv-btn {
  flex: 1; min-height: 54px; border: 0; border-radius: 16px;
  background: rgba(255, 255, 255, 0.16); color: #fff; font-size: 16px; font-weight: 700;
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  transition: transform 0.25s var(--spring);
}
.pv-btn.primary { flex: 1.5; background: #fff; color: #111114; }
.pv-btn:active { transform: scale(0.97); }
.pv:not([hidden]) .pv-actions, .pv:not([hidden]) .pv-x { animation: fade-in 0.4s ease 0.5s both; }

/* ---------- motion, reduced ---------- */

@media (prefers-reduced-motion: reduce) {
  .rl-strip,
  .row.enter, .row.exit,
  .c, .s, .c.land, .c.leave, .c.flip, .c.flag::before, .c.next::after,
  .s.drop, .s.bump, .s .ring, .s .ring .tk path, .ring.pop,
  .hint.gone, .hint-demo, .hint-install.in, .fin-btn.in,
  .last > .in, .okbtn, .okbtn.stamp,
  .slot .d, .slot .d.next::after, .slot .dg, .slot.shake,
  .key, .key.down,
  .toast.in, .call.in, .call.out,
  .demo-bar, .db-btn, .db-start, .db-sound,
  .scrim, .sheet, .sh-btn,
  .finish, .fin-card, .fin-btn,
  .rl.in, .rs.in,
  .app, .top, .money, .mh-label.swap, .mh-offchip, .mh-off.gone, .mh-price,
  .st.enter, .st-v.bump, .fr-custom, .seg button, .seg-thumb, .mn-btn,
  .pv, .pv-paper.print, .pv-paper.rise, .pv-stamp.land, .pv-stamp.soft, .pv-fx i,
  .pv-actions, .pv-x, .pv-btn {
    animation: none !important;
    transition: none !important;
  }
  body, .rows, .entry { transition: none; }
  /* With no fade to end on, the call has to be put away outright. */
  .call.out { opacity: 0; }
}
