/* ==========================================================================
   Liquid glass materials
   Loaded after theme.css, so it builds on the theme tokens and can still be
   overridden per theme below.

   Glass only reads as glass when there is something behind it to refract. The
   application background is a flat wash, so this file also lays down a fixed
   field of soft colour for the panels to pick up. Without that, translucency
   just looks like a slightly wrong shade of the background.
   ========================================================================== */

:root {
  /* The pane itself. Deliberately far from clear: text sits on these surfaces
     and has to stay readable over whatever scrolls underneath, so this is a
     frosted pane, not a window. */
  --glass-bg: rgba(255, 255, 255, 0.72);
  --glass-bg-strong: rgba(255, 255, 255, 0.86);
  --glass-bg-faint: rgba(255, 255, 255, 0.55);

  /* Saturation is what stops a blur looking like grey haze: it pulls the
     colour out of whatever is behind and keeps the warmth of the palette. */
  --glass-blur: saturate(180%) blur(20px);
  --glass-blur-sm: saturate(160%) blur(12px);
  --glass-blur-lg: saturate(190%) blur(34px);

  /* The lit top edge that gives a pane thickness. */
  --glass-edge: inset 0 1px 0 rgba(255, 255, 255, 0.85);
  --glass-edge-soft: inset 0 1px 0 rgba(255, 255, 255, 0.6);
  --glass-rim: rgba(255, 255, 255, 0.55);

  /* The frame a widget's panel sits on. Fainter than the pane, so more of the
     ambient field shows through it -- which is what makes it read as the
     muted outer band rather than a second sheet of the same glass. */
  --glass-frame: rgba(228, 224, 219, 0.85);

  --glass-shadow: 0 6px 24px rgba(76, 52, 42, 0.10), 0 1px 2px rgba(76, 52, 42, 0.05);
  --glass-shadow-lg: 0 24px 60px rgba(76, 52, 42, 0.18), 0 2px 6px rgba(76, 52, 42, 0.07);

  /* The ambient field behind the glass. */
  /* Damped. At the old strengths these four washed the page warm enough that
     it read as cream whatever --bg said -- most of why the background looked
     yellow rather than like paper. Enough colour is left for the glass to
     have something to pick up. */
  --amb-1: rgba(224, 120, 93, 0.12);
  --amb-2: rgba(139, 123, 184, 0.10);
  --amb-3: rgba(74, 157, 127, 0.08);
  --amb-4: rgba(217, 160, 91, 0.07);
}

/* ---------- Dark ---------- */
:root[data-theme="dark"] {
  --glass-bg: rgba(23, 20, 19, 0.74);
  --glass-bg-strong: rgba(23, 20, 19, 0.90);
  --glass-bg-faint: rgba(23, 20, 19, 0.58);

  --glass-edge: inset 0 1px 0 rgba(255, 255, 255, 0.14);
  --glass-edge-soft: inset 0 1px 0 rgba(255, 255, 255, 0.09);
  --glass-rim: rgba(255, 255, 255, 0.13);
  --glass-frame: rgba(3, 2, 2, 0.62);

  --glass-shadow: 0 6px 24px rgba(0, 0, 0, 0.42), 0 1px 2px rgba(0, 0, 0, 0.30);
  --glass-shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.58), 0 2px 6px rgba(0, 0, 0, 0.35);

  /* The field was only ever set once, in light, so these same four blooms sat
     behind the dark theme at full strength -- which is why a near-black
     palette still came out looking like warm brown. Dark needs far less: a
     little for the glass to refract, and no more. */
  --amb-1: rgba(224, 120, 93, 0.09);
  --amb-2: rgba(139, 123, 184, 0.08);
  --amb-3: rgba(74, 157, 127, 0.06);
  --amb-4: rgba(217, 160, 91, 0.05);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --glass-bg: rgba(23, 20, 19, 0.74);
    --glass-bg-strong: rgba(23, 20, 19, 0.90);
    --glass-bg-faint: rgba(23, 20, 19, 0.58);

    --glass-edge: inset 0 1px 0 rgba(255, 255, 255, 0.14);
    --glass-edge-soft: inset 0 1px 0 rgba(255, 255, 255, 0.09);
    --glass-rim: rgba(255, 255, 255, 0.13);
    --glass-frame: rgba(3, 2, 2, 0.62);

    --glass-shadow: 0 6px 24px rgba(0, 0, 0, 0.42), 0 1px 2px rgba(0, 0, 0, 0.30);
    --glass-shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.58), 0 2px 6px rgba(0, 0, 0, 0.35);

    /* Damped for dark, as above. */
    --amb-1: rgba(224, 120, 93, 0.09);
    --amb-2: rgba(139, 123, 184, 0.08);
    --amb-3: rgba(74, 157, 127, 0.06);
    --amb-4: rgba(217, 160, 91, 0.05);
  }
}

/* --------------------------------------------------------------------------
   Ambient field
   Fixed, behind everything, pointer-events:none so it never intercepts a tap.
   Four soft blooms rather than one gradient, so a panel moving over it picks
   up a changing colour instead of a uniform tint.
   -------------------------------------------------------------------------- */
body.app-shell::before {
  content: "";
  position: fixed;
  inset: -20vmax;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(38vmax 38vmax at 12% 8%, var(--amb-1), transparent 62%),
    radial-gradient(42vmax 42vmax at 88% 14%, var(--amb-2), transparent 64%),
    radial-gradient(36vmax 36vmax at 78% 88%, var(--amb-3), transparent 62%),
    radial-gradient(34vmax 34vmax at 18% 82%, var(--amb-4), transparent 62%);
  filter: blur(28px);
}

/* --------------------------------------------------------------------------
   The material
   -------------------------------------------------------------------------- */
.card,
.sidebar,
.topbar,
.popover,
.modal-card,
.assistant-card,
.user-chip,
.icon-btn,
.bottom-nav,
.notif-head,
.device-row,
.push-banner {
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
}

.card {
  background: var(--glass-bg);
  /* The shorthand above resets background-clip, so it has to be restated or
     the pane floods its own frame. */
  background-clip: padding-box;
  border: var(--frame) solid var(--glass-frame);
  box-shadow: 0 0 0 1px var(--glass-rim), var(--glass-shadow), var(--glass-edge-soft);
}

/* A pane lifts toward the light rather than just growing a shadow. */
.card:hover {
  box-shadow: 0 0 0 1px var(--glass-rim), var(--glass-shadow-lg), var(--glass-edge);
}

.sidebar {
  background: var(--glass-bg);
  border-right: 1px solid var(--glass-rim);
  box-shadow: var(--glass-edge-soft);
}

/* Strong, not faint, and at rest rather than only once scrolled.

   The page scrolls underneath this bar, and at the faint alpha a heading
   passing beneath stayed legible through it -- two lines of text occupying
   the same strip of screen, which is what reads as the bar and the page
   overlapping. Blur alone does not fix that: it smears the text without
   hiding it.

   The faint value was right when this bar had nothing moving behind it. It no
   longer does, so the only thing left for is-stuck to say is that there is
   something above -- which is a shadow, not a colour. */
.topbar {
  background: var(--glass-bg-strong);
  border-bottom: 1px solid var(--glass-rim);
}

.topbar.is-stuck {
  box-shadow: var(--glass-shadow), var(--glass-edge-soft);
}

.popover,
.theme-menu,
.tt-overflow-menu {
  background: var(--glass-bg-strong);
  -webkit-backdrop-filter: var(--glass-blur-lg);
  backdrop-filter: var(--glass-blur-lg);
  border: 1px solid var(--glass-rim);
  box-shadow: var(--glass-shadow-lg), var(--glass-edge);
}

.modal-card {
  background: var(--glass-bg-strong);
  background-clip: padding-box;
  -webkit-backdrop-filter: var(--glass-blur-lg);
  backdrop-filter: var(--glass-blur-lg);
  border: var(--frame) solid var(--glass-frame);
  box-shadow: 0 0 0 1px var(--glass-rim), var(--glass-shadow-lg), var(--glass-edge);
}

.bottom-nav {
  background: var(--glass-bg-strong);
  /* All round: it floats clear of the screen edge, so there is no edge for a
     top border alone to sit against. */
  border: 1px solid var(--glass-rim);
  box-shadow: 0 12px 32px rgba(76, 52, 42, 0.16), 0 2px 8px rgba(76, 52, 42, 0.08), var(--glass-edge);
}

.icon-btn,
.user-chip {
  background: var(--glass-bg-faint);
  border: 1px solid var(--glass-rim);
  box-shadow: var(--glass-edge-soft);
}

.icon-btn:hover {
  background: var(--glass-bg);
  box-shadow: var(--glass-shadow), var(--glass-edge);
}

.assistant-card,
.push-banner,
.notif-head,
.device-row {
  background: var(--glass-bg-faint);
  border: 1px solid var(--glass-rim);
}

/* Buttons get the thickness without the blur: they are small and numerous,
   and a backdrop-filter on each one is the quickest way to make scrolling
   stutter on a phone. */
.btn {
  box-shadow: var(--glass-edge-soft), var(--shadow-xs);
}

.btn-primary {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.34), 0 4px 14px var(--primary-ring);
}

/* The backdrop behind a dialog: darkened and blurred, so the sheet in front
   of it reads as the only thing in focus. */
.modal-backdrop {
  -webkit-backdrop-filter: saturate(120%) blur(10px);
  backdrop-filter: saturate(120%) blur(10px);
}

/* --------------------------------------------------------------------------
   Fallbacks
   -------------------------------------------------------------------------- */

/* No backdrop-filter (older Firefox, some Android WebViews): translucent
   panels would show the ambient blooms straight through the text. Go opaque. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card, .sidebar, .topbar, .popover, .modal-card, .bottom-nav,
  .theme-menu, .tt-overflow-menu, .icon-btn, .user-chip,
  .assistant-card, .push-banner, .notif-head, .device-row {
    background: var(--surface);
  }
  body.app-shell::before { opacity: 0.45; }
}

/* Someone who has asked for less transparency has usually asked because the
   effect makes text hard to read. Honour it literally. */
@media (prefers-reduced-transparency: reduce) {
  .card, .sidebar, .topbar, .popover, .modal-card, .bottom-nav,
  .theme-menu, .tt-overflow-menu, .icon-btn, .user-chip,
  .assistant-card, .push-banner, .notif-head, .device-row {
    background: var(--surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  body.app-shell::before { display: none; }
}

/* Stacked blurs are the expensive part, and a phone pays for it on every
   scroll frame. Lighten the radii rather than dropping the look. */
@media (max-width: 768px) {
  :root {
    --glass-blur: saturate(170%) blur(14px);
    --glass-blur-lg: saturate(180%) blur(22px);
  }
  body.app-shell::before { filter: blur(36px); }
}


/* ==========================================================================
   Parallax on the field behind everything

   Skiper55's shape: something behind the content moving at a fraction of the
   scroll, so the page reads as having depth rather than as one flat sheet.

   The source parallaxes an image. This application has no hero photographs to
   move -- it is a timetable -- but it does have a layer that plays exactly
   that part: the ambient field these panels are translucent against. It is on
   every page behind the login, which is where this was asked for, and moving
   it costs nothing that content can notice, because nothing is written on it.

   A fraction of the distance, not all of it. The field is inset far past the
   viewport on every side, so it can drift this far and still have no visible
   edge to run out of.
   ========================================================================== */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    body.app-shell::before {
      animation: ambientParallax linear both;
      /* The document's own scroller: the field is fixed to the viewport, not
         to any panel inside it. */
      animation-timeline: scroll(root block);
    }

    @keyframes ambientParallax {
      from { translate: 0 0; }
      to   { translate: 0 -11vmax; }
    }
  }
}
