/* ==========================================================================
   Liquid Glass Design System — the material
   --------------------------------------------------------------------------
   One material, six weights. Every surface in the blog is `.glass` plus a
   modifier; nothing in components.css re-implements the look, it only picks
   a weight and a radius.

   Anatomy of a surface:

     background-color   the tint  — a wash so text always has contrast
     backdrop-filter    the body  — blur + saturation + (Chromium) refraction
     ::before           the depth — top-light gradient + inner edge glow
     box-shadow         the rim   — inset shine + cast shadow

   The refraction itself comes from an SVG displacement map generated per
   element size by js/glass/glass-sdf.js + glass-core.js, which set --g-filter
   on the element. Where that is unsupported the var stays empty and the surface
   degrades to blur + tint, which still reads as glass.
   ========================================================================== */

.glass {
  /* Custom properties inherit, so a child surface would silently reuse its
     parent's filter (built for a different size) before the adapter reaches
     it. Declaring it empty here stops that at every surface boundary. */
  --g-filter: ;

  position: relative;
  isolation: isolate;
  border-radius: var(--g-radius, var(--g-r-lg));
  background-color: var(--g-tint);
  border: 1px solid var(--g-edge);
  box-shadow: var(--g-shine), var(--g-shadow);
  color: var(--g-ink);

  -webkit-backdrop-filter:
    var(--g-filter, ) blur(var(--g-blur))
    saturate(var(--g-saturate)) brightness(var(--g-brightness))
    contrast(var(--g-contrast));
  backdrop-filter:
    var(--g-filter, ) blur(var(--g-blur))
    saturate(var(--g-saturate)) brightness(var(--g-brightness))
    contrast(var(--g-contrast));

  transition:
    background-color var(--g-dur) var(--g-ease),
    box-shadow       var(--g-dur) var(--g-ease),
    transform        var(--g-dur) var(--g-spring),
    border-radius    var(--g-dur) var(--g-spring);
}

/* Depth. A single top-light gradient does most of the work of making a flat
   translucent rectangle read as a solid piece of glass with thickness.

   The gradient lives in --g-highlight rather than inline on ::before, because
   themes with their own :before on a surface (Butterfly's archive node is one)
   have to restate it to take the pseudo back, and a variable is the only way
   to do that without copying the ramp around. */
:root {
  /* A narrow streak, not a wash: light glancing off a curved top edge.
     A full-surface gradient here is what makes glass look like frost. */
  --g-highlight:
    linear-gradient(
      158deg,
      rgba(255, 255, 255, 0.60) 0%,
      rgba(255, 255, 255, 0.16) 7%,
      rgba(255, 255, 255, 0.00) 18%,
      rgba(255, 255, 255, 0.00) 78%,
      rgba(255, 236, 202, 0.14) 93%,
      rgba(255, 246, 226, 0.42) 100%
    );
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --g-highlight:
      linear-gradient(
        158deg,
        rgba(255, 236, 212, 0.30) 0%,
        rgba(255, 236, 212, 0.08) 9%,
        rgba(255, 255, 255, 0.00) 22%,
        rgba(255, 255, 255, 0.00) 82%,
        rgba(255, 190, 130, 0.12) 100%
      );
  }
}

:root[data-theme="dark"] {
  --g-highlight:
    linear-gradient(
      158deg,
      rgba(255, 236, 212, 0.30) 0%,
      rgba(255, 236, 212, 0.08) 9%,
      rgba(255, 255, 255, 0.00) 22%,
      rgba(255, 255, 255, 0.00) 82%,
      rgba(255, 190, 130, 0.12) 100%
    );
}

.glass::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  /* §12 — the highlight is independent of refraction. Its overall strength is
     the one optical knob that can be read straight out of CSS, which keeps the
     PoC control panel and future tuning panels free of any JS coupling. */
  opacity: var(--glass-highlight-intensity, 0.9);
  background: var(--g-highlight);
}


/* ==========================================================================
   Specificity bridge
   --------------------------------------------------------------------------
   Butterfly styles its shells through id selectors (`#recent-posts
   .recent-post-item`, `#aside-content .card-widget`, …), which outrank a bare
   `.glass`. Rather than sprinkle !important through the material, the surface
   list is restated once here at matching specificity. article.css and
   components.css load after this file and can still refine any of it.
   ========================================================================== */

#nav.glass,
#recent-posts .recent-post-item.glass,
#aside-content .card-widget.glass,
#card-toc.glass,
#post.glass, #page.glass, #archive.glass, #tag.glass, #category.glass,
#rightside button.glass,
#pagination .page-number.glass, #pagination .extend.glass,
#tag .tag-cloud-list a.glass,
.tag-cloud-list a.glass,
#article-container .tag-list a.glass,
#article-container figure.highlight.glass,
#article-container pre.glass,
#article-container blockquote.glass,
#article-container .table-wrap.glass,
#article-container .note.glass,
#local-search .search-dialog.glass,
#sidebar-menus.glass,
#body-wrap .toggle-menu-dialog.glass {
  background-color: var(--g-tint);
  background-image: none;
  border: 1px solid var(--g-edge);
  border-radius: var(--g-radius, var(--g-r-lg));
  box-shadow: var(--g-shine), var(--g-shadow);

  /* Butterfly reaches most of these shells through `transition: all` --
     .cardHover in _global/function.styl, and a dozen more in _layout. `all`
     registers a transition for every animatable longhand, layout ones
     included: border widths, padding, margin, height. A home page carried
     over 400 of them, so any unrelated style change -- a theme flip, a
     performance tier stepping down, a resize -- animated layout properties on
     every surface at once, and each of those surfaces is running a
     backdrop-filter. Restating the material's own four here, at the
     specificity the rest of this block already needed, confines it to the
     properties the design actually animates. */
  transition:
    background-color var(--g-dur) var(--g-ease),
    box-shadow       var(--g-dur) var(--g-ease),
    transform        var(--g-dur) var(--g-spring),
    border-radius    var(--g-dur) var(--g-spring);
}

#nav.glass--interactive:hover,
#recent-posts .recent-post-item.glass--interactive:hover,
#aside-content .card-widget.glass--interactive:hover,
#rightside button.glass--interactive:hover,
#pagination .page-number.glass--interactive:hover,
#pagination .extend.glass--interactive:hover,
#tag .tag-cloud-list a.glass--interactive:hover,
.tag-cloud-list a.glass--interactive:hover,
#article-container .tag-list a.glass--interactive:hover {
  background-color: var(--g-tint-hover);
  box-shadow: var(--g-shine), var(--g-shadow-lift);
}

/* Butterfly reads --card-bg in a handful of places we have not enumerated;
   pointing it at the tint keeps those in the system too. */
.glass {
  --card-bg: var(--g-tint);
}

/* ==========================================================================
   Weights
   --------------------------------------------------------------------------
                refraction  transparency  blur   edge     used by
     soft            low        high       med    low     navbar, tags, pills
     medium          med        med        med    med     aside, TOC
     strong          high       med        high   high     article, post cards
     dense           low        low        high   high     code, table, quote
     floating        high       high       high   high     modal, search
     lens            high       highest     none   high     avatar dome
   ========================================================================== */

.glass--soft {
  --g-radius: var(--g-r-pill);
  --g-blur: 0px;
  --glass-refraction: 34;
  --glass-bezel-width: 20;
  --glass-edge-depth: 2.2;
  --glass-chromatic: 0.030;
  --g-tint: rgba(255, 249, 240, 0.07);
  --g-tint-hover: rgba(255, 249, 240, 0.15);
}

.glass--medium {
  --g-radius: var(--g-r-lg);
  --g-blur: 0px;
  --glass-refraction: 60;
  --glass-bezel-width: 74;
  --glass-edge-depth: 1.65;
  --glass-chromatic: 0.028;
}

.glass--strong {
  --g-radius: var(--g-r-xl);
  --g-blur: 0px;
  --glass-refraction: 94;
  --glass-bezel-width: 100;
  --glass-edge-depth: 1.55;
  --glass-chromatic: 0.026;
  --g-tint: rgba(255, 250, 243, 0.09);
  --g-tint-hover: rgba(255, 250, 243, 0.18);
}

/* Dense — code, tables, quotes.
   This was the one weight that never actually read as glass. A 72% tint with
   2px of blur behind it is a frosted slab, and the bezel was both too narrow
   and too weak (28 over 22px, against strong's 94 over 100px) to bend anything
   a reader would notice. Both are now in line with the rest of the system: no
   frost at all, a real refracting rim, and a tint low enough to let the page
   show through the face.

   The tint is the one number here that cannot simply be minimised. These
   surfaces carry light text -- a dark pane is what keeps a code block readable
   over a bright page -- so it has to stay dark enough to hold that contrast.
   Half opacity is about where it still reads as dark glass rather than as
   either a solid block or unreadable code. */
.glass--dense {
  --g-radius: var(--g-r-md);
  --g-blur: 0px;
  --glass-refraction: 58;
  --glass-bezel-width: 48;
  --glass-edge-depth: 1.9;
  --glass-chromatic: 0.024;
  /* Light, and translucent enough to actually be glass. The dark slab this
     used to be existed to carry light text; the ink is tokenised now, so the
     pane can be a pane. */
  --g-tint: rgba(255, 252, 246, 0.44);
  --g-tint-hover: rgba(255, 252, 246, 0.52);
  --g-saturate: 1.2;
  color: var(--g-code-ink);
}

.glass--floating {
  --g-radius: var(--g-r-xl);
  --g-blur: 0px;
  --glass-refraction: 84;
  --glass-bezel-width: 88;
  --glass-edge-depth: 1.6;
  --glass-chromatic: 0.030;
  --g-tint: rgba(255, 250, 243, 0.12);
  --g-shadow: var(--g-shadow-lift);
}

/* Dark theme adjustments per weight. Only the tints move; the geometry of
   the material is theme-independent. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .glass--soft {
    --g-tint: rgba(92, 68, 50, 0.14);
    --g-tint-hover: rgba(112, 84, 62, 0.26);
  }
  :root:not([data-theme="light"]) .glass--strong {
    --g-tint: rgba(84, 62, 46, 0.22);
    --g-tint-hover: rgba(100, 74, 56, 0.32);
  }
  :root:not([data-theme="light"]) .glass--dense {
    --g-tint: rgba(24, 17, 13, 0.56);
    --g-tint-hover: rgba(24, 17, 13, 0.62);
  }
  :root:not([data-theme="light"]) .glass--floating {
    --g-tint: rgba(84, 62, 46, 0.24);
  }
}

[data-theme="dark"] .glass--soft {
  --g-tint: rgba(92, 68, 50, 0.14);
  --g-tint-hover: rgba(112, 84, 62, 0.26);
}
[data-theme="dark"] .glass--strong {
  --g-tint: rgba(84, 62, 46, 0.22);
  --g-tint-hover: rgba(100, 74, 56, 0.32);
}
[data-theme="dark"] .glass--dense {
  --g-tint: rgba(24, 17, 13, 0.56);
  --g-tint-hover: rgba(24, 17, 13, 0.62);
}
[data-theme="dark"] .glass--floating {
  --g-tint: rgba(84, 62, 46, 0.24);
}

/* ==========================================================================
   Interaction
   ========================================================================== */

.glass--interactive {
  cursor: pointer;
}

.glass--interactive:hover {
  background-color: var(--g-tint-hover);
  box-shadow: var(--g-shine), var(--g-shadow-lift);
}

.glass--interactive:active {
  transform: scale(0.985);
  transition-duration: var(--g-dur-fast);
}

/* Touch press (§43): a short compression with a spring return. The class is
   toggled by glass-motion.js on pointerdown / pointerup. */
.glass--pressed {
  transform: scale(0.985);
  box-shadow: var(--g-shine), var(--g-shadow);
  transition-duration: var(--g-dur-fast);
}

/* --------------------------------------------------------------------------
   Morphing (§16) — small-to-large stretch instead of an opacity fade.
   glass-motion.js marks overlays with .glass-morph-in the moment they open.
   -------------------------------------------------------------------------- */

@keyframes g-morph-in {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: scale(1); }
}

/* The drawer is deliberately not in this list. It opens by transform — the
   theme slides it in from off-screen — and an animation on `transform` wins
   over the class that does the sliding, so morphing it meant the panel hung
   off the right edge for the length of the animation and then snapped into
   place. Its own slide is the morph. */
#local-search .search-dialog.glass-morph-in,
.search-dialog.glass-morph-in {
  animation: g-morph-in 0.42s var(--g-spring);
}

/* --------------------------------------------------------------------------
   CSS renderer edge ring (§34) — the non-Chromium path has no displacement,
   so the silhouette has to carry the "thick glass" reading on its own.
   -------------------------------------------------------------------------- */

html.glass-css .glass {
  --g-blur: 3px;
  box-shadow:
    var(--g-shine),
    inset 0 0 0 1px rgba(255, 255, 255, 0.30),
    var(--g-shadow);
}
