/* Liquid Glass — an optional interface style, off by default.
 *
 * ---------------------------------------------------------------------------
 * TO REMOVE THIS ONE THEME, delete these three things and nothing else:
 *
 *   1. this file
 *   2. the <link> to it in index.html, settings.html and admin.html
 *   3. 'glass' from the THEMES list in those three boot scripts and in
 *      settings.js, and its button in the theme grid in settings.html
 *
 * The engine it hangs off is shared now and outlives it: data-ui on the root
 * element, an allowlist, and a stylesheet per theme. The other themes are
 * palettes and live together in themes.css; this one is a construction rather
 * than a palette, which is why it is still a file of its own.
 *
 * Every rule below is scoped to `[data-ui="glass"]`, so with the attribute
 * absent -- which is the default, and what every existing reader gets -- this
 * file contributes nothing at all. No token in app.css was changed to make it
 * work and no markup was added for it to hook onto.
 * ---------------------------------------------------------------------------
 *
 * What it is. The app already paints glass in places; this makes it the whole
 * surface treatment, the way a modern map application does. Three ideas, and
 * everything here is one of them:
 *
 *   Surfaces float. They are detached from the edges of the screen, rounded on
 *   every corner, and shadowed as though they were a few millimetres above the
 *   map rather than stuck to it.
 *
 *   Surfaces are lit. A hairline along the top edge catches the light and the
 *   bottom edge falls into shadow, which is what makes a translucent panel
 *   read as a pane of something rather than as a hole in the page.
 *
 *   Surfaces are thick. Heavier blur and more saturation than the default, so
 *   what is behind them reads as colour and movement rather than as detail --
 *   the point of frosting is that you can tell something is there.
 *
 * What it deliberately does not touch: the drawer's geometry. Its height, its
 * transform and its resting position are load-bearing for the drag, and are
 * measured in JavaScript. Everything here is paint -- background, border,
 * radius, shadow, filter -- so the sheet still measures exactly what it did.
 */

:root[data-ui="glass"] {
  /* Thicker than the default's blur(22px) saturate(165%). */
  --glass-blur: blur(30px) saturate(180%);

  /* The panes themselves. Alpha rather than a solid, because a pane that is
     not translucent is just a darker rectangle. */
  --g-pane: rgba(20, 27, 46, .58);
  --g-pane-2: rgba(31, 41, 68, .55);
  --g-raised: rgba(26, 35, 58, .72);

  /* The light. A pane is edged twice: a bright hairline where it faces the
     light and a dark one where it does not, which is most of what sells the
     thickness. */
  --g-edge: rgba(255, 255, 255, .16);
  --g-edge-lit: rgba(255, 255, 255, .34);
  --g-edge-dim: rgba(6, 10, 20, .55);

  /* Contact shadow tight and dark, ambient shadow wide and soft. One alone
     reads as a sticker; the pair reads as height. */
  --g-lift: 0 1px 1px rgba(4, 7, 16, .34), 0 2px 6px rgba(4, 7, 16, .28),
            0 18px 40px -14px rgba(4, 7, 16, .72);
  --g-lift-lo: 0 1px 1px rgba(4, 7, 16, .3), 0 8px 20px -10px rgba(4, 7, 16, .6);

  --g-r: 22px;
  --g-r-lg: 28px;

  /* Text goes up a little. Contrast against a moving photograph is worse than
     against a flat panel, and this is the whole reason a glass interface can
     end up less readable than the thing it replaced. */
  --ink: #F2F6FF;
  --ink-2: #B3C1DC;
  --ink-3: #8494B4;
  --line: rgba(255, 255, 255, .12);
  --shadow: var(--g-lift);
}

/* Light mode wants the same construction with the light coming from a white
   ground rather than a dark one, or the panes turn into grey smears. */
:root[data-ui="glass"][data-theme="light"] {
  --g-pane: rgba(255, 255, 255, .66);
  --g-pane-2: rgba(255, 255, 255, .52);
  --g-raised: rgba(255, 255, 255, .82);
  --g-edge: rgba(255, 255, 255, .8);
  --g-edge-lit: rgba(255, 255, 255, 1);
  --g-edge-dim: rgba(18, 32, 60, .12);
  --g-lift: 0 1px 1px rgba(16, 32, 62, .1), 0 2px 6px rgba(16, 32, 62, .08),
            0 18px 40px -14px rgba(16, 32, 62, .28);
  --g-lift-lo: 0 1px 1px rgba(16, 32, 62, .08), 0 8px 20px -10px rgba(16, 32, 62, .22);
  --ink: #0A1120;
  --ink-2: #40506E;
  --ink-3: #6B7B99;
  --line: rgba(18, 32, 60, .1);
}

/* The shared construction, so it is written once and applied by name. */
:root[data-ui="glass"] .searchbox,
:root[data-ui="glass"] .mapctl-group,
:root[data-ui="glass"] .fab,
:root[data-ui="glass"] .brandfloat,
:root[data-ui="glass"] .avwrap,
:root[data-ui="glass"] .dropdown,
:root[data-ui="glass"] .picker-menu,
:root[data-ui="glass"] .modal-card,
:root[data-ui="glass"] .msgcard,
:root[data-ui="glass"] .installcard,
:root[data-ui="glass"] .card,
:root[data-ui="glass"] .sidebar,
:root[data-ui="glass"] .maplibregl-popup-content {
  background: var(--g-pane);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--g-edge);
  box-shadow: var(--g-lift);
}

/* The lit edge. A pseudo-element rather than a second border, because a border
   is one colour on all four sides and light is not.
   Not on .fab: it is already a gradient with a glow of its own, and the one
   thing it must not get is the position change below. */
:root[data-ui="glass"] .searchbox::before,
:root[data-ui="glass"] .mapctl-group::before,
:root[data-ui="glass"] .card::before,
:root[data-ui="glass"] .modal-card::before,
:root[data-ui="glass"] .msgcard::before,
:root[data-ui="glass"] .dropdown::before,
:root[data-ui="glass"] .picker-menu::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  /* Bright at the top, gone by a third of the way down. */
  background: linear-gradient(180deg, var(--g-edge-lit), transparent 34%);
  /* Only the 1px rim, not the fill: the mask keeps the gradient in the border
     box and punches out the middle. */
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  padding: 1px;
  z-index: 1;
}
/* Anything carrying that highlight has to be a positioning context for it --
   but only the ones that do not already have a position of their own.
   .fab, .dropdown and .picker-menu are all `absolute`, and setting them
   `relative` drops them back into the flow: the compose button went from the
   bottom-right corner of the map to sixty pixels above the top-left of it,
   off the screen entirely. .modal-card is already relative. */
:root[data-ui="glass"] .searchbox,
:root[data-ui="glass"] .mapctl-group,
:root[data-ui="glass"] .card,
:root[data-ui="glass"] .msgcard { position: relative; }

/* --- the map's own chrome -------------------------------------------------- */

:root[data-ui="glass"] .searchbox {
  border-radius: var(--g-r-lg);
}
:root[data-ui="glass"] .mapctl-group,
:root[data-ui="glass"] .fab,
:root[data-ui="glass"] .brandfloat,
:root[data-ui="glass"] .avwrap {
  border-radius: 50%;
}
/* The compose button keeps its colour -- it is the one control that is an
   action rather than a surface, and glassing it would lose that. */
:root[data-ui="glass"] .fab {
  background: var(--grad);
  border-color: var(--g-edge-lit);
  box-shadow: var(--g-lift), 0 0 24px -6px var(--purple-500);
}

/* --- the feed -------------------------------------------------------------- */

:root[data-ui="glass"] .card {
  border-radius: var(--g-r);
  box-shadow: var(--g-lift-lo);
}
/* The drawer is glass over a moving map, so the cards inside it are glass over
   glass -- which stacks into mud. They go lighter and thinner instead, and
   take their separation from the shadow rather than from the fill. */
:root[data-ui="glass"] .sidebar .card {
  background: var(--g-pane-2);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
:root[data-ui="glass"] .card-media { border-radius: 16px; }

/* The composer, which is the one surface whose background is load-bearing.
 *
 * It is deliberately not in the list above. That rule replaces `background`
 * outright, and the compose sheet's background is not decoration: its last
 * stretch fades onto --compose-ground, and the strip along the bottom of an
 * installed iPhone -- the part of the screen no page is allowed to paint -- is
 * set to that same token so the two meet in one colour. Glass replaced the
 * gradient with a flat pane, the fade went, and the band stopped matching the
 * sheet above it.
 *
 * The blue claim survived it by accident: that one is a ::after overlay
 * carrying its own copy of the fade, which nothing here touches. So the seam
 * only showed on the default claim, which is the one most people see.
 *
 * Layered rather than replaced: the glass pane goes underneath, the fade stays
 * on top of it, and the bottom stop is opaque -- so the sheet still ends on
 * exactly --compose-ground whatever is behind it. */
:root[data-ui="glass"] .compose-sheet {
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, 0) 62%, var(--compose-ground) 100%),
    var(--g-pane);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--g-edge);
  box-shadow: var(--g-lift);
}

/* The drawer. Paint only: its height, transform and resting position are
   measured in JavaScript and must not move. */
:root[data-ui="glass"] .sidebar {
  border-radius: var(--g-r-lg) var(--g-r-lg) 0 0;
  border-bottom: 0;
}
:root[data-ui="glass"] .feedhead {
  /* It lies over the list and hides what passes beneath, so it cannot be
     translucent -- see the note on background-color: inherit in app.css. */
  background: var(--g-raised);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}

/* --- controls -------------------------------------------------------------- */

:root[data-ui="glass"] .btn,
:root[data-ui="glass"] .picker-btn,
:root[data-ui="glass"] .querychip,
:root[data-ui="glass"] .segmented,
:root[data-ui="glass"] .minitag,
:root[data-ui="glass"] .followbtn {
  background: var(--g-pane-2);
  border: 1px solid var(--g-edge);
  backdrop-filter: blur(12px) saturate(160%);
  -webkit-backdrop-filter: blur(12px) saturate(160%);
}
:root[data-ui="glass"] .btn-primary {
  background: var(--grad);
  border-color: var(--g-edge-lit);
}
:root[data-ui="glass"] .btn:hover,
:root[data-ui="glass"] .picker-btn:hover { border-color: var(--g-edge-lit); }

/* --- everything that covers the whole screen ------------------------------- */

:root[data-ui="glass"] .modal-card,
:root[data-ui="glass"] .msgcard,
:root[data-ui="glass"] .compose-sheet { border-radius: var(--g-r-lg); }

:root[data-ui="glass"] .modal::backdrop,
:root[data-ui="glass"] .lightbox {
  backdrop-filter: blur(10px) saturate(120%);
  -webkit-backdrop-filter: blur(10px) saturate(120%);
}

/* --- the pages that are not the map --------------------------------------- */
/* They have no map behind them, so there is nothing to see through. They get
   the shape and the light and skip the blur, which would cost a compositing
   layer for no visible gain. */

:root[data-ui="glass"] .page-rail,
:root[data-ui="glass"] .sset.card,
:root[data-ui="glass"] .dash-card,
:root[data-ui="glass"] .dash-stat,
:root[data-ui="glass"] .feedrow,
:root[data-ui="glass"] .switchbar,
:root[data-ui="glass"] .rail-nav {
  border-radius: var(--g-r);
  border: 1px solid var(--g-edge);
  box-shadow: var(--g-lift-lo);
}
:root[data-ui="glass"] .page-rail {
  border-radius: 0;
  box-shadow: none;
  background: var(--g-pane);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}

/* --- restraint ------------------------------------------------------------- */

/* Blur is the expensive part, and a phone that has already told us it is short
   of memory should not be asked for a dozen compositing layers on top of a
   WebGL context. The shape and the light survive; the frosting does not. */
@media (max-width: 900px) {
  :root[data-ui="glass"] .sidebar .card {
    box-shadow: none;
    border-color: var(--line);
  }
}

@media (prefers-reduced-transparency: reduce) {
  :root[data-ui="glass"] * {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  :root[data-ui="glass"] .searchbox,
  :root[data-ui="glass"] .mapctl-group,
  :root[data-ui="glass"] .card,
  :root[data-ui="glass"] .modal-card,
  :root[data-ui="glass"] .msgcard { background: var(--panel); }
}
