/* Liquid-glass integration layer.
   Loads after vendor/liquid-glass/liquid-glass.css and adapts it to this app:
   a backdrop for the glass to work against, dark-theme tinting, and the
   contrast fixes translucent surfaces always need.
   Nothing in vendor/ is edited — all local changes live here. */

/* ---------------------------------------------------------------- backdrop */
/* A fixed grid of faded blue dots, lit by soft bands of brightness that sweep
   across it — the dots never move, the light does.

   The trick: .dots is masked into a dot pattern, so anything painted inside it
   is only visible at the dot positions. The .wave children are plain gradients
   that slide underneath that mask. Only their transform animates, so the
   compositor owns the whole effect and the main thread stays free for typing.
   No canvas, no per-dot elements, no JavaScript. */

:root {
  --dot: #2f6bed;
  --dot-rest: rgba(47, 107, 237, .09);   /* the grid at its dimmest */
  --dot-peak: rgba(47, 107, 237, .30);   /* a dot inside the wave */
}

/* body must not paint a background of its own: a block-level box background is
   painted after negative-z-index descendants, so an opaque body would bury the
   backdrop. html keeps the base colour and propagates it to the canvas. */
body { background: transparent; }

.backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  background: var(--bg);
  pointer-events: none;
}

.dots {
  position: absolute;
  inset: 0;
  background: var(--dot-rest);
  -webkit-mask-image: radial-gradient(#000 1.7px, transparent 1.9px);
  mask-image: radial-gradient(#000 1.7px, transparent 1.9px);
  -webkit-mask-size: 30px 30px;
  mask-size: 30px 30px;
}

/* Oversized so a band is always mid-sweep and its edges never show. */
.wave {
  position: absolute;
  inset: -55%;
  will-change: transform;
}

/* Two bands at different angles and speeds. Where they cross, dots peak
   brighter — that interference is what stops it reading as a metronome. */
.w1 {
  background: linear-gradient(112deg,
    transparent 34%, var(--dot-peak) 47%, var(--dot-peak) 53%, transparent 66%);
  animation: wave-1 14s ease-in-out infinite alternate;
}
.w2 {
  background: linear-gradient(68deg,
    transparent 38%, var(--dot-peak) 49%, transparent 62%);
  opacity: .7;
  animation: wave-2 21s ease-in-out infinite alternate;
}

/* alternate + ease-in-out: the band eases to a stop and returns, so there is
   no jump-cut at the loop point the way a linear one-way sweep would give. */
@keyframes wave-1 {
  from { transform: translate3d(-26%, -14%, 0); }
  to { transform: translate3d(26%, 14%, 0); }
}
@keyframes wave-2 {
  from { transform: translate3d(22%, -10%, 0); }
  to { transform: translate3d(-22%, 10%, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .wave { animation: none; opacity: .35; }
}

/* ------------------------------------------------------- glass host surfaces */
/* The library injects an absolutely-positioned child at z-index -1, so every
   host has to be transparent or it would cover its own glass. */

.btn.primary,
.sheet,
.login-card .field,
.note,
.currency,
.icon-btn,
.pill,
.day {
  background: transparent;
}

/* Softer than the library default: its 2px white border reads as a hard edge
   against a dark UI. */
input.liquid-glass-direct,
textarea.liquid-glass-direct,
[class*="liquid-glass-direct"] {
  border: 1px solid rgba(255, 255, 255, .75);
}

/* -------------------------------------------------------------- components */

/* Primary actions (Save, Continue) — the surfaces that should read as solid
   glass rather than a hint, so they still look like the thing to press. */
.btn.primary {
  color: var(--fg);
  border-radius: 20px;
  overflow: hidden;
}
.btn.primary > .liquid-glass { background: rgba(255, 255, 255, .5); }

/* Currency toggle: a small glass lozenge under the amount. */
.currency {
  border: 0;
  color: var(--fg);
  opacity: .85;
  border-radius: 999px;
  overflow: hidden;
}
.currency:active { opacity: 1; }

/* Note field: glass pill instead of the underline. */
.note {
  border-bottom: 0;
  border-radius: 16px;
  padding: 15px 18px;
}
.note:focus { border-bottom-color: transparent; }

.icon-btn, .pill { border-radius: 999px; overflow: hidden; }
.pill { border: 0; color: var(--fg); opacity: .85; }

.login-card .field { border: 0; border-radius: 16px; }
/* The glass overlay inherits its host's radius, so the host needs one. */
.login-card { border-radius: 24px; padding: 22px; overflow: hidden; }

/* Menu sheet: the big glass panel. */
.sheet {
  border-radius: 26px 26px 0 0;
  overflow: hidden;
}
.sheet-backdrop { background: rgba(15, 23, 42, .22); }
.sheet-item { border-top-color: rgba(0, 0, 0, .1); }
.sheet-item:active { background: rgba(0, 0, 0, .06); }

/* Sticky day header floats as glass while rows scroll under it. */
.day {
  padding: 14px 16px 12px;
  overflow: hidden;
}
.row { border-top-color: rgba(0, 0, 0, .08); }

/* ----------------------------------------------------------------- motion */
/* Presses are driven by the Web Animations API in motion.js. The old CSS
   :active transform would fight it, so it stands down here. */
.btn:active,
.icon-btn:active {
  transform: none;
}

/* Dispersion rim — the coloured fringe glass throws at its edges, as on the
   iOS 26 tab lozenge. A hue wheel drawn only in a 1.5px band around the
   control: the two masks cover the whole box and the padding box, and
   compositing them with xor leaves just the difference, i.e. the border.

   It starts from --gradient-angle, the same variable the specular highlight
   uses, so the colours sit where the light is rather than in a fixed place. */
.rim {
  position: absolute;
  inset: 0;
  z-index: 3;
  padding: 1.5px;
  border-radius: inherit;
  pointer-events: none;
  background: conic-gradient(
    from var(--gradient-angle, 135deg),
    #ff375f, #ff9f0a, #ffd60a, #32d74b, #40c8e0,
    #0a84ff, #bf5af2, #ff375f
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: xor;
  /* Blurring the ring is what turns a hard rainbow outline into light
     scattering through an edge. Softer than it looks like it should be —
     a crisp rainbow border reads as a sticker, not as glass. */
  filter: blur(1.6px) saturate(1.35);
  opacity: 0;
  transition: opacity .34s cubic-bezier(.22, 1, .36, 1);
}

/* Fast bloom under the finger, slow decay on release — light appearing at the
   edge the instant the surface is loaded, then bleeding away. */
.is-pressed .rim {
  opacity: .45;
  transition-duration: .11s;
}

@media (prefers-reduced-motion: reduce) {
  .rim { transition-duration: .01s; }
}

/* --------------------------------------------------------------- contrast */
/* Translucency costs legibility. Text sitting on glass gets a faint shadow so
   it stays readable when a bright part of the backdrop drifts underneath. */

.amount, .btn.primary, .row-note, .row-amount, .topbar-title, .who-name,
.sheet-item, .login-title {
  text-shadow: 0 1px 2px rgba(255, 255, 255, .6);
}

/* Placeholders lose contrast fastest against a moving backdrop. */
.amount::placeholder { color: rgba(120, 130, 150, .35); }
.note::placeholder, .field::placeholder { color: var(--muted); }
