/* ============================================================
   Balance — Budget ONE design language
   Dark-first: near-black background, dark gray-blue cards,
   indigo accent, mint/red money colors, bold numerals.
   Light counterpart follows the system. Ref: dribbble.com/shots/24906105.
   ============================================================ */

:root {
  --bg: #0a0a0e;
  --card: #14141b;
  --card-2: #1b1b24;          /* pressed / nested surfaces */
  --fill: #1e1e28;            /* inputs, chips */
  --skel: #1e1e28;            /* loading placeholder block */
  --skel-hi: #2b2b38;         /* the sweep that crosses it */
  --text: #f4f4f8;
  --text-2: #9a9ca8;
  --text-3: #5b5d6a;
  --hairline: rgba(244, 244, 248, 0.06);
  --accent: #6366f1;
  --accent-press: #4f52e0;
  --pos: #2ee27a;
  --neg: #e05252;
  --pos-fill: rgba(46, 226, 122, 0.12);
  --neg-fill: rgba(224, 82, 82, 0.12);
  --shadow-sheet: 0 -12px 48px rgba(0, 0, 0, 0.6);
  --backdrop: rgba(0, 0, 0, 0.6);
  --card-shadow: none;
  --toast-bg: #24242e;
  --toast-text: #f4f4f8;
  /* per-person tint (avatars, person name) */
  --av-bg-s: 40%;
  --av-bg-l: 16%;
  --av-fg-s: 75%;
  --av-fg-l: 70%;
}

/* light counterpart — same language, inverted surfaces */
@media (prefers-color-scheme: light) {
  :root {
    --bg: #f3f3f6;
    --card: #ffffff;
    --card-2: #ffffff;
    --fill: #ebebf1;
    /* Darker than --fill: a placeholder has to read on --card (#fff) and on the
       page (#f3f3f6) alike, and the sweep must not go brighter than the page or
       the block vanishes at the peak. */
    --skel: #dcdce4;
    --skel-hi: #eeeef2;
    --text: #101015;
    --text-2: #696d7a;
    --text-3: #9fa2ad;
    --hairline: rgba(16, 16, 24, 0.09);
    --accent: #5457e6;
    --accent-press: #4346d4;
    --pos: #129c5c;
    --neg: #d03a30;
    --pos-fill: rgba(18, 156, 92, 0.12);
    --neg-fill: rgba(208, 58, 48, 0.1);
    --shadow-sheet: 0 -12px 48px rgba(20, 20, 45, 0.18);
    --backdrop: rgba(18, 18, 28, 0.38);
    --card-shadow: 0 1px 2px rgba(16, 16, 40, 0.04), 0 6px 20px rgba(16, 16, 40, 0.06);
    --toast-bg: #17171e;
    --toast-text: #f4f4f8;
    --av-bg-s: 62%;
    --av-bg-l: 93%;
    --av-fg-s: 52%;
    --av-fg-l: 38%;
  }
}

* { margin: 0; padding: 0; box-sizing: border-box; }

[hidden] { display: none !important; }

html { height: 100%; }

body {
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  height: 100dvh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  touch-action: manipulation;
}

input {
  font: inherit;
  color: var(--text);
  user-select: text;
  -webkit-user-select: text;
}

/* ============ App shell / views ============ */

#app {
  position: fixed;
  inset: 0;
  overflow: hidden;
}

.view {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  transition: transform 0.32s cubic-bezier(0.32, 0.72, 0.28, 1);
  overflow: hidden;
}

.view-right { transform: translateX(100%); z-index: 6; }

.view-right.active { transform: translateX(0); }

/* ============ Home ============ */

.home-header {
  padding: calc(env(safe-area-inset-top) + 16px) 20px 0;
}

.home-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.home-title-row h1 {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.header-actions { display: flex; gap: 8px; }

.icon-btn {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text);
  background: var(--card);
  box-shadow: var(--card-shadow);
  transition: background 0.12s, transform 0.1s, color 0.12s;
}

.icon-btn:active { background: var(--fill); transform: scale(0.92); color: var(--text); }

/* net balance — dark card, big white numeral */
.summary-card {
  margin: 18px 0 14px;
  background: var(--card);
  box-shadow: var(--card-shadow);
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 24px 22px;
}

.summary-label {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-2);
}

.summary-label.centered { text-align: center; margin-bottom: 6px; }

/* amount + percentage row, like "$26,950   %43" */
.amount-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.bar-pct {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* split progress bar: green = received share, red = sent share */
.flow-bar {
  width: 100%;
  height: 6px;
  border-radius: 4px;
  background: var(--neg);
  overflow: hidden;
  margin-top: 10px;
}

.flow-bar.empty { background: var(--fill); }

.flow-fill {
  height: 100%;
  border-radius: 4px;
  background: var(--pos);
  transition: width 0.4s cubic-bezier(0.32, 0.72, 0.28, 1);
}

.flow-sub {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  margin-top: 8px;
  font-size: 12.5px;
  font-weight: 500;
}

.fs-sent { color: var(--text-2); }
.fs-received { color: var(--text); }

.summary-amount {
  font-size: 38px;
  font-weight: 750;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--text);
}

/* direction shown by the label color, numeral stays white */
.summary-amount.pos, .summary-amount.neg { color: var(--text); }

#net-label.pos { color: var(--pos); }
#net-label.neg { color: var(--neg); }

.pos { color: var(--pos); }
.neg { color: var(--neg); }

.search-wrap {
  margin: 0 20px 8px;
  display: flex;
  align-items: center;
  gap: 9px;
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: 13px;
  padding: 0 13px;
  color: var(--text-3);
}

.search-wrap input {
  flex: 1;
  border: none;
  outline: none;
  background: none;
  height: 42px;
  font-size: 15px;
}

.search-wrap input::placeholder { color: var(--text-3); }

.people-list {
  flex: 1;
  overflow-y: auto;
  padding: 2px 20px calc(env(safe-area-inset-bottom) + 40px);
}

/* flat rows, hairline separated, like the records list */
.person-row {
  display: flex;
  align-items: center;
  gap: 13px;
  width: 100%;
  padding: 14px 2px;
  text-align: left;
  transition: opacity 0.12s;
}

.person-row + .person-row { border-top: 1px solid var(--hairline); }

.person-row:active { opacity: 0.55; }

/* category-icon style avatars: dark tint, colored glyph */
.avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  font-weight: 650;
  background: hsl(var(--av-h, 240) var(--av-bg-s) var(--av-bg-l));
  color: hsl(var(--av-h, 240) var(--av-fg-s) var(--av-fg-l));
}

.person-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.person-row-name {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.person-row-sub { font-size: 12.5px; color: var(--text-3); }

.person-row-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
  flex-shrink: 0;
}

.person-row-amount {
  font-size: 15.5px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.person-row-tag {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
}

.person-row-amount.settled { color: var(--text-3); font-weight: 500; }

/* ============ Person view ============ */

.person-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: calc(env(safe-area-inset-top) + 10px) 14px 6px;
}

.person-header .icon-btn { background: none; border: none; }

.person-name {
  flex: 1;
  min-width: 0;
  text-align: center;
  color: hsl(var(--av-h, 240) var(--av-fg-s) var(--av-fg-l));
  font-size: 18px;
  font-weight: 650;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.balance-banner {
  margin: 8px 20px 4px;
  background: var(--card);
  box-shadow: var(--card-shadow);
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  padding: 22px 20px;
}

.balance-banner-label {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-2);
}

.balance-banner-amount {
  font-size: 32px;
  font-weight: 750;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--text);
}

.balance-banner.get .balance-banner-label { color: var(--pos); }
.balance-banner.give .balance-banner-label { color: var(--neg); }
.balance-banner.zero .balance-banner-amount { color: var(--text-3); }

.txn-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px 20px calc(env(safe-area-inset-bottom) + 118px);
}

.txn-date-header {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-2);
  margin: 22px 2px 6px;
}

.txn-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 2px;
  text-align: left;
  transition: opacity 0.12s;
}

.txn-row + .txn-row { border-top: 1px solid var(--hairline); }

.txn-row:active { opacity: 0.55; }

.txn-icon {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-weight: 650;
}

.txn-icon.sent { background: var(--neg-fill); color: var(--neg); }
.txn-icon.received { background: var(--pos-fill); color: var(--pos); }

.txn-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.txn-title {
  font-size: 15px;
  font-weight: 550;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.txn-title.untitled { color: var(--text-3); font-weight: 450; }

.txn-sub { font-size: 12px; color: var(--text-3); }

.txn-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
  flex-shrink: 0;
}

.txn-amount {
  font-size: 15.5px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.txn-date { font-size: 12px; color: var(--text-3); }

.txn-amount.sent { color: var(--neg); }
.txn-amount.received { color: var(--pos); }

/* ============ Bottom action bar ============ */

.action-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  gap: 10px;
  padding: 16px 20px calc(env(safe-area-inset-bottom) + 18px);
  background: linear-gradient(to top, var(--bg) 70%, transparent);
}

.action-bar button {
  flex: 1;
  height: 52px;
  border-radius: 26px;
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  background: var(--card);
  box-shadow: var(--card-shadow);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: transform 0.12s, background 0.12s;
}

.action-bar button:active { transform: scale(0.96); background: var(--fill); }

.action-bar .arr { font-weight: 700; }

.arr.sent { color: var(--neg); }
.arr.received { color: var(--pos); }

/* ============ Empty states ============ */

.empty-state {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 40px;
  pointer-events: none;
}

.empty-state h2 {
  font-size: 16.5px;
  font-weight: 650;
  margin-bottom: 6px;
  letter-spacing: -0.01em;
}

.empty-state p {
  font-size: 14px;
  color: var(--text-2);
  max-width: 240px;
  line-height: 1.45;
}

/* ============ Sheet / backdrop ============ */

#backdrop {
  position: fixed;
  inset: 0;
  background: var(--backdrop);
  z-index: 40;
  opacity: 0;
  transition: opacity 0.28s ease;
}

#backdrop.show { opacity: 1; }

#sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  background: var(--card);
  border-top: 1px solid var(--hairline);
  border-radius: 30px 30px 0 0;
  box-shadow: var(--shadow-sheet);
  padding: 10px 22px calc(env(safe-area-inset-bottom) + 22px);
  transform: translateY(100%);
  transition: transform 0.32s cubic-bezier(0.32, 0.72, 0.28, 1);
  max-height: 88dvh;
  overflow-y: auto;
}

#sheet.show { transform: translateY(0); }

.sheet-handle {
  width: 34px;
  height: 4px;
  border-radius: 3px;
  background: var(--fill);
  margin: 4px auto 18px;
}

.sheet-title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 18px;
}

.field { margin-bottom: 14px; }

.field label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-2);
  margin-bottom: 7px;
}

.field input {
  width: 100%;
  height: 50px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--fill);
  padding: 0 15px;
  font-size: 16px;
  font-weight: 500;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.field input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.18);
}

.amount-field input {
  font-size: 23px;
  font-weight: 700;
  height: 58px;
  font-variant-numeric: tabular-nums;
}

/* type tabs — colored text + underline, like Add Record */
.seg {
  display: flex;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 18px;
}

.seg button {
  flex: 1;
  height: 44px;
  font-size: 14.5px;
  font-weight: 550;
  color: var(--text-2);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 0.15s, border-color 0.15s;
}

.seg button.on { font-weight: 650; }
.seg button.on.sent { color: var(--neg); border-bottom-color: var(--neg); }
.seg button.on.received { color: var(--pos); border-bottom-color: var(--pos); }

.sheet-primary {
  width: 100%;
  height: 52px;
  border-radius: 26px;
  background: var(--accent);
  color: #fff;
  font-size: 16px;
  font-weight: 650;
  margin-top: 8px;
  box-shadow: 0 6px 22px rgba(99, 102, 241, 0.35);
  transition: transform 0.12s, background 0.15s, opacity 0.15s;
}

.sheet-primary:active { transform: scale(0.97); background: var(--accent-press); }

.sheet-primary:disabled { opacity: 0.45; }

/* Privacy · Terms at the foot of the account sheet. Plain links — they navigate
   away from the app shell, which is fine: there is no in-app state to lose. */
.sheet-legal {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin-top: 18px;
  font-size: 12.5px;
  color: var(--text-3);
}

.sheet-legal a { color: var(--text-2); text-decoration: none; }

.sheet-danger {
  width: 100%;
  height: 48px;
  border-radius: 15px;
  background: var(--neg-fill);
  color: var(--neg);
  font-size: 15px;
  font-weight: 600;
  margin-top: 10px;
  transition: background 0.15s, color 0.15s;
}

.sheet-danger.confirm { background: var(--neg); color: #fff; }

/* ============ Toast ============ */

#toast {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom) + 96px);
  transform: translate(-50%, 16px);
  background: var(--toast-bg);
  color: var(--toast-text);
  font-size: 13.5px;
  font-weight: 550;
  padding: 10px 18px;
  border-radius: 100px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s, transform 0.25s;
  z-index: 60;
  max-width: 84vw;
  text-align: center;
}

#toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ============ Loading shimmers ============ */
/* #app carries `loading` in the markup, so the very first frame is already the
   placeholder. Without it the shell paints a real "₹0" and a settled label —
   somebody else's number, effectively, until /api/state answers. app.js drops the
   class once it has, and a 401 never drops it: the browser is on its way to
   /login.html and no wrong figure was ever on screen.

   The people list needs no class of its own. Its placeholder rows sit in the
   markup and renderHome() overwrites the whole list on its first pass, so they
   clear themselves. */
#app.loading .summary-label,
#app.loading .summary-amount,
#app.loading .bar-pct,
#app.loading .flow-bar,
#app.loading .fs-sent,
#app.loading .fs-received,
.skel-avatar,
.skel-line {
  /* Text stays in place and stays measured — it is just not readable, so a block
     the width of the real thing needs no hardcoded size. */
  color: transparent;
  background-color: var(--skel);
  background-image: linear-gradient(
    90deg,
    transparent 0%,
    var(--skel-hi) 50%,
    transparent 100%
  );
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: skel-shimmer 1.4s ease-in-out infinite;
  border-radius: 8px;
}

/* The card is a stretch-aligned flex column, so the label would otherwise become a
   full-width bar, and "₹0" is narrow enough that the amount would be a small
   square. Both are given the proportions of the thing they stand in for. */
#app.loading .summary-label {
  align-self: center;
  width: 108px;
}

#app.loading .summary-amount { min-width: 168px; }

/* These three are empty in the shell, so there is nothing to take a width from. */
#app.loading .bar-pct,
#app.loading .fs-sent,
#app.loading .fs-received {
  display: inline-block;
  min-height: 0.85em;
}

#app.loading .bar-pct { min-width: 34px; }
#app.loading .fs-sent,
#app.loading .fs-received { min-width: 88px; }

/* The green fill is a share of a total nobody has sent yet. */
#app.loading .flow-bar > .flow-fill { display: none; }

@keyframes skel-shimmer {
  from { background-position: -50% 0; }
  to { background-position: 150% 0; }
}

/* Matches .person-row's box exactly — same gap, same padding, same 44px circle —
   so the real rows land where the placeholders were instead of shifting. */
.person-row-skel {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 14px 2px;
}

.person-row-skel + .person-row-skel { border-top: 1px solid var(--hairline); }

.skel-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Widths live here, not on the elements: `style-src 'self'` has no
   'unsafe-inline', so a style attribute would be blocked outright. */
.skel-line {
  height: 11px;
  border-radius: 6px;
}

.person-row-skel:nth-child(1) .skel-line { width: 42%; }
.person-row-skel:nth-child(2) .skel-line { width: 58%; }
.person-row-skel:nth-child(3) .skel-line { width: 34%; }

/* Loading is the one place a static placeholder says nothing at all, so the
   blocks stay and only the sweep stops. */
@media (prefers-reduced-motion: reduce) {
  #app.loading .summary-label,
  #app.loading .summary-amount,
  #app.loading .bar-pct,
  #app.loading .flow-bar,
  #app.loading .fs-sent,
  #app.loading .fs-received,
  .skel-avatar,
  .skel-line {
    background-image: none;
    animation: none;
  }
}

/* ============ Signed out ============ */
/* The one screen shown without a session. Same language as the deleted lock
   screen: centered column, logo tile, indigo accent. */

#signedout {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  z-index: 20; /* above the app views, below nothing — sheets never coexist with it */
  padding: 24px;
}

.signedout-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: 100%;
  max-width: 320px;
  /* Sits a touch above true center, like the lock screen did. */
  margin-bottom: 8vh;
}

/* ---- Holding the sign-in page back until we know it is wanted ----

   This page is static and CloudFront cannot read a cookie, so login.js has to
   ASK /auth/me whether the visitor already has a session — and one who does is
   sent straight to /home.html. Painting the whole page immediately means that
   visitor sees a flash of a sign-in page they never needed, which is every
   launch of the Mac app: it opens at this URL by design (mac/src-tauri/src/lib.rs).

   So the whole column waits and a LOADING STATE stands in its place: the logo,
   centred on the screen, with three dots under it. It shows what belongs to
   NEITHER answer, so nothing wrong is ever on screen, and it reads as a launch
   screen on purpose rather than as a page that stopped halfway.

   The splash carries its own logo (see login.html) instead of the column's. That
   is what buys the centring: the column keeps its natural position — a touch
   above centre, 8vh of bottom margin — while the wait sits at the true middle of
   the screen, and the two CROSS-FADE. The logo therefore appears to travel to its
   place without anything measuring the distance, which a translate would have to
   do and would get wrong the day the column's content changes.

   The cost, and it is a real reversal: the logo now moves at reveal. The earlier
   version held the column's children and left the logo painted in place
   precisely so nothing moved. Centring the wait and keeping the logo still are
   not both available; the cross-fade is what makes the move deliberate.

   login.js adds .ready to #signedout the moment the answer is "nobody" — the
   class is on the SECTION, not the column, because it now governs both the column
   and the splash. Each of the two has a pair of animations: a delayed one for the
   fallback, and a same-shape one under .ready that runs at once.

   Those pairs have DIFFERENT NAMES on purpose, and it is not cosmetic. Changing
   animation-name restarts an animation, so the fade always runs from its start;
   reusing one name and dropping the delay only retimes the animation already
   running, and once the wait has outlasted the 200ms duration, retiming lands
   past the end and the column snaps into place. Transitions do not work here
   either — the reveal has to remove a filling animation, and removing one starts
   no transition (verified: the fade was instant until these became keyframes).

   The delay is only a FALLBACK, for when no answer ever comes, so a visitor is
   never left staring at a logo forever. 1s, so that it never fires ahead of a
   real answer — a cold round trip is ~150–300ms once DNS, TCP and TLS are paid
   for, and well past that on a poor connection.

   Note which failures the fallback actually covers, because it is narrower than
   it looks: login.js reveals the page the moment Store.me() SETTLES, and a
   rejection counts, so an unreachable API is an instant reveal rather than a
   wait. What is left is JavaScript that never ran or was blocked, and a request
   that hangs without ever rejecting. Those are the cases that wait the full 1s —
   which is also why the fallback has to stay CSS, not a setTimeout. */
.signedout-inner > * {
  opacity: 0;
  animation: signedout-reveal 200ms ease 1s both;
}

/* The answer arrived and it is "not signed in" — fade the column in now. */
#signedout.ready .signedout-inner > * {
  animation: signedout-reveal-now 200ms ease both;
}

@keyframes signedout-reveal {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes signedout-reveal-now {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* The loading state. Fixed and content-centred, so it is the middle of the
   SCREEN rather than the top of the column.

   The LOGO is what gets centred, not the logo and dots as a group — which is why
   the dots are taken out of flow below rather than being a second grid row. In
   flow they push the logo up by half their own height, and "nearly centred" is
   the kind of near-miss that reads as an accident. */
.signedout-splash {
  position: fixed;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  /* Never a click target. It covers the whole screen and, once faded, stays
     there at opacity 0 — so without this it would quietly swallow every tap on
     the sign-in link behind it. */
  pointer-events: none;
  animation: signedout-splash-out 150ms ease 1s both;
}

#signedout.ready .signedout-splash {
  animation: signedout-splash-out-now 150ms ease both;
}

@keyframes signedout-splash-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes signedout-splash-out-now {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* The splash logo is the column's logo in every respect — same size, radius and
   shadow — because the cross-fade has to read as one object, not two. Only the
   margin goes: it is centred, so it carries no spacing of its own. */
.signedout-splash .signedout-logo { margin-bottom: 0; }

/* Held back 300ms of their own. On a fast answer the wait is over before these
   ever appear, and a 30ms flash of a loading indicator is precisely the
   unintentional look the loading state exists to avoid. */
.signedout-dots {
  display: flex;
  gap: 6px;
  /* Out of flow, so the logo above stays exactly centred. 64px = half the 72px
     logo, putting this at its bottom edge, plus 28px of air. Tied to the logo's
     size: change one and change the other. */
  position: absolute;
  top: calc(50% + 64px);
  left: 50%;
  transform: translateX(-50%);
  animation: signedout-dots-in 160ms ease 300ms both;
}

.signedout-dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-2);
  animation: signedout-dot 1.2s ease-in-out infinite;
}

/* Staggered, which is what makes three dots read as progress rather than as a
   blinking row. */
.signedout-dots span:nth-child(2) { animation-delay: 160ms; }
.signedout-dots span:nth-child(3) { animation-delay: 320ms; }

@keyframes signedout-dots-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes signedout-dot {
  0%, 100% { opacity: 0.25; transform: scale(0.85); }
  50% { opacity: 1; transform: scale(1); }
}

/* The only looping motion on the page, so it is the only thing that has to go.
   The fades stay: they are opacity, not movement, and losing them would put the
   snap back. */
@media (prefers-reduced-motion: reduce) {
  .signedout-dots span {
    animation: none;
    opacity: 0.55;
  }
}

.signedout-logo {
  width: 72px;
  height: 72px;
  border-radius: 16px;
  box-shadow: var(--card-shadow);
  display: block;
  margin-bottom: 20px;
}

.signedout-title {
  font-size: 28px;
  font-weight: 750;
  letter-spacing: -0.5px;
}

/* "by ⊙ Transactor" — the parent brand: its circular mark and its wordmark
   face. Caveat runs small for its point size, so the wordmark is set larger
   than the "by"; centering (not baseline) keeps the icon on the line. */
.signedout-brand {
  font-size: 13px;
  color: var(--text-2);
  margin-top: 2px;
  display: flex;
  align-items: center;
  gap: 6px;
  /* it is a link to transactor.app, but dressed as the byline it always was */
  text-decoration: none;
}

.signedout-brandmark {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

/* Transactor's scheme, spoken in Balance's tokens: a text-colored circle with
   background-colored arrows, so it inverts with the color scheme exactly as
   the original does on transactor.app. */
.signedout-brandmark circle { fill: var(--text); }
.signedout-brandmark path { stroke: var(--bg); }

.signedout-wordmark {
  font-family: "Caveat", cursive;
  font-weight: 600;
  font-size: 22px;
  color: var(--text);
}

.signedout-sub {
  font-size: 14.5px;
  color: var(--text-3);
  margin-top: 14px;
  margin-bottom: 28px;
}

/* An <a> wearing the primary-button clothes. Kept its own rule rather than
   reusing .sheet-primary, which is sized for the bottom sheet. */
.signedout-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 52px;
  border-radius: 26px;
  background: var(--accent);
  color: #fff;
  font-size: 16px;
  font-weight: 650;
  text-decoration: none;
  box-shadow: 0 6px 22px rgba(99, 102, 241, 0.35);
  transition: transform 0.12s, background 0.15s;
}

.signedout-btn:active {
  transform: scale(0.97);
  background: var(--accent-press);
}

.signedout-note {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-3);
  margin-top: 18px;
}

/* Privacy · Terms, under the note. The landing page's equivalent lives in
   site.css — this page loads styles.css and never sees that file. */
.signedout-legal {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin-top: 14px;
  font-size: 12.5px;
  color: var(--text-3);
}

.signedout-legal a { color: var(--text-2); text-decoration: none; }

.signedout-legal a:hover { color: var(--text); }

/* ============ Account sheet ============ */

.account-email {
  font-size: 14px;
  color: var(--text-2);
  margin: -8px 0 16px;
  min-height: 18px;
}

/* A row-shaped link out to Transactor, dressed like the app's inputs. */
.account-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--fill);
  color: var(--text);
  font-size: 15px;
  font-weight: 550;
  text-decoration: none;
  margin-bottom: 14px;
}

.account-link:active { opacity: 0.6; }

.account-brandmark {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

/* The mark sits on the fill chip, so its arrows take that surface's color. */
.account-brandmark circle { fill: var(--text); }
.account-brandmark path { stroke: var(--fill); }

/* Desktop: center the app like a phone */
@media (min-width: 520px) {
  #app {
    max-width: 430px;
    left: 50%;
    transform: translateX(-50%);
    border-left: 1px solid var(--hairline);
    border-right: 1px solid var(--hairline);
  }
  #sheet { max-width: 430px; left: 50%; margin-left: -215px; }
}
