/* Custom CSS for Glance.
 *
 * RULE: never hardcode a colour, size or font here. Glance exposes 63 CSS
 * custom properties on :root and its themes redefine only a handful of roots
 * (--bgh/--bgs/--bgl, --color-primary, --cm, --tsm) from which the rest derive.
 * Anything built from those variables follows the theme picker automatically,
 * including light mode. A literal value is the moment this file starts drifting
 * from the theme instead of tracking it.
 */

/* ── Make the card carousel usable with a mouse ───────────────────────────────
 * The strip is already scrollable (.cards-horizontal sets overflow-x: auto,
 * scrollbar-width: thin) and trackpad side-swipe works. But macOS uses OVERLAY
 * scrollbars that fade out unless "Show scroll bars: Always" is set, so a mouse
 * user has nothing to grab and the strip reads as static.
 *
 * Styling ::-webkit-scrollbar forces a classic, always-present scrollbar in
 * Chrome and Safari, which restores the drag handle. Firefox keeps its own thin
 * scrollbar and just takes the colours.
 */
.cards-horizontal::-webkit-scrollbar {
  height: 8px;
}

.cards-horizontal::-webkit-scrollbar-track {
  background: var(--color-widget-background-highlight);
  border-radius: var(--border-radius);
}

.cards-horizontal::-webkit-scrollbar-thumb {
  background: var(--color-text-subdue);
  border-radius: var(--border-radius);
}

.cards-horizontal::-webkit-scrollbar-thumb:hover {
  background: var(--color-primary);
}

/* Firefox */
.cards-horizontal {
  scrollbar-color: var(--color-text-subdue) var(--color-widget-background-highlight);
}

/* Snap to card edges so a drag or swipe lands cleanly rather than mid-card.
 * `proximity` rather than `mandatory`: it tidies up where a scroll ends without
 * fighting the user mid-gesture. */
.cards-horizontal {
  scroll-snap-type: x proximity;
}

.cards-horizontal > * {
  scroll-snap-align: start;
}

/* ── Service icons, tinted to the active accent ──────────────────────────────
 *
 * Matthew, 2026-08-10: "if they were svgs and could recolor based on material
 * that would be amazing."
 *
 * They can, and the mechanism is a CSS MASK. The SVG stops being a picture and
 * becomes a STENCIL: the element paints a flat background colour, and the mask
 * decides where that paint lands. So the icon takes whatever colour we point at
 * it, and the shape is the only thing the file contributes.
 *
 * The colour is `--color-primary`, which is a Glance theme variable — so this
 * needs no wallpaper-specific rule and no `photo` gate. Under Catppuccin Mocha
 * the icons are Mauve, under Latte they follow Latte, and under `photo` the
 * theme widget overwrites --color-primary with the hue derived from the current
 * wallpaper. The icons then RE-TINT EVERY HOUR with the image, for free.
 *
 * Two overrides are load-bearing:
 *   width/height 0 + padding — an <img> renders its own pixels over any
 *     background, so the replaced content is collapsed to nothing and the
 *     padding box becomes the visible area. There is no property that says
 *     "keep the box, drop the picture".
 *   filter:none — Glance applies grayscale(0.4) to these icons, which would
 *     desaturate the tint we just applied.
 *
 * The two -mono files are Simple Icons rather than selfh.st: their selfh.st
 * versions draw interior detail in WHITE, which a mask cannot distinguish from
 * filled, so both flattened to a solid blob. They are RENAMED rather than
 * replaced in place because the URL is the cache key — swapping the bytes behind
 * an unchanged URL left every browser that had already fetched it showing the
 * old, broken icon, with nothing on the server to point at.
 *
 * Ember's PNG is left alone. Her icon is a PHOTOGRAPH, and a mask would flatten
 * her into a silhouette — a stencil is the right treatment for a logo and the
 * wrong one for a face.
 *
 * ⚠️ THE FILL IS SCOPED TO THE ICONS THAT HAVE A STENCIL, and that is the whole
 * reason this is a selector list rather than [src$=".svg"]. The wildcard painted
 * the flat colour on every SVG, so an icon with no mask rule rendered as the
 * fill with nothing cut out of it — a solid mauve square. It looked like a
 * broken image and was in fact a missing line, which is the worst pairing: the
 * page said "no icon" when the truth was "this icon is not in the list yet".
 * The services page added six at once and every one of them was a square.
 * Unlisted SVGs now fall through to Glance's own flat-icon treatment: not
 * theme-tinted, but legible, and visibly a logo rather than a defect.
 */
.monitor-site-icon[src*="/matrix.svg"],
.monitor-site-icon[src*="/emby.svg"],
.monitor-site-icon[src*="/headscale.svg"],
.monitor-site-icon[src*="/home-assistant-mono.svg"],
.monitor-site-icon[src*="/roon.svg"],
.monitor-site-icon[src*="/audiobookshelf-mono.svg"],
.monitor-site-icon[src*="/portainer.svg"],
.monitor-site-icon[src*="/ember.svg"],
.monitor-site-icon[src*="/openai.svg"],
.monitor-site-icon[src*="/lmstudio.svg"],
.monitor-site-icon[src*="/pixiv.svg"],
.monitor-site-icon[src*="/go.svg"],
.monitor-site-icon[src*="/proxmox.svg"],
.monitor-site-icon[src*="/forgejo.svg"],
.monitor-site-icon[src*="/tailscale.svg"],
.monitor-site-icon[src*="/pihole.svg"],
.monitor-site-icon[src*="/uptimekuma.svg"],
.monitor-site-icon[src*="/vaultwarden.svg"],
.monitor-site-icon[src*="/element.svg"],
.monitor-site-icon[src*="/grafana.svg"] {
  width: 0;
  height: 0;
  padding: 1.6rem;                 /* matches Glance's own 3.2rem box */
  box-sizing: content-box;
  background-color: var(--color-primary);
  filter: none;
  opacity: 1;
  -webkit-mask-repeat: no-repeat;          mask-repeat: no-repeat;
  -webkit-mask-position: center;           mask-position: center;
  -webkit-mask-size: contain;              mask-size: contain;
  transition: background-color .3s;
}

.monitor-site-icon[src*="/matrix.svg"]         { -webkit-mask-image: url(/assets/icons/matrix.svg);         mask-image: url(/assets/icons/matrix.svg); }
.monitor-site-icon[src*="/emby.svg"]           { -webkit-mask-image: url(/assets/icons/emby.svg);           mask-image: url(/assets/icons/emby.svg); }
.monitor-site-icon[src*="/headscale.svg"]      { -webkit-mask-image: url(/assets/icons/headscale.svg);      mask-image: url(/assets/icons/headscale.svg); }
.monitor-site-icon[src*="/home-assistant-mono.svg"] { -webkit-mask-image: url(/assets/icons/home-assistant-mono.svg); mask-image: url(/assets/icons/home-assistant-mono.svg); }
.monitor-site-icon[src*="/roon.svg"]           { -webkit-mask-image: url(/assets/icons/roon.svg);           mask-image: url(/assets/icons/roon.svg); }
.monitor-site-icon[src*="/audiobookshelf-mono.svg"] { -webkit-mask-image: url(/assets/icons/audiobookshelf-mono.svg); mask-image: url(/assets/icons/audiobookshelf-mono.svg); }
.monitor-site-icon[src*="/portainer.svg"]      { -webkit-mask-image: url(/assets/icons/portainer.svg);      mask-image: url(/assets/icons/portainer.svg); }
.monitor-site-icon[src*="/ember.svg"]          { -webkit-mask-image: url(/assets/icons/ember.svg);          mask-image: url(/assets/icons/ember.svg); }

/* The services page, vendored from Simple Icons rather than loaded from their
 * CDN. `si:` in Glance config emits a jsdelivr URL, which the BROWSER fetches —
 * an external dependency on a self-hosted dashboard, and the same objection
 * already written down against the community weather widget. Held locally they
 * also mask, so they retint with the wallpaper like every other icon here. */
.monitor-site-icon[src*="/openai.svg"]         { -webkit-mask-image: url(/assets/icons/openai.svg);         mask-image: url(/assets/icons/openai.svg); }
.monitor-site-icon[src*="/lmstudio.svg"]       { -webkit-mask-image: url(/assets/icons/lmstudio.svg);       mask-image: url(/assets/icons/lmstudio.svg); }
.monitor-site-icon[src*="/pixiv.svg"]          { -webkit-mask-image: url(/assets/icons/pixiv.svg);          mask-image: url(/assets/icons/pixiv.svg); }
.monitor-site-icon[src*="/go.svg"]             { -webkit-mask-image: url(/assets/icons/go.svg);             mask-image: url(/assets/icons/go.svg); }
.monitor-site-icon[src*="/grafana.svg"]        { -webkit-mask-image: url(/assets/icons/grafana.svg);        mask-image: url(/assets/icons/grafana.svg); }

/* The Estate page (estate.yml), vendored the same way: simple-icons 16.32.0 from
 * the npm registry, tarball sha512 checked against the registry's integrity field
 * (2026-09-23). CC0; the marks belong to their projects. */
.monitor-site-icon[src*="/proxmox.svg"] { -webkit-mask-image: url(/assets/icons/proxmox.svg); mask-image: url(/assets/icons/proxmox.svg); }
.monitor-site-icon[src*="/forgejo.svg"] { -webkit-mask-image: url(/assets/icons/forgejo.svg); mask-image: url(/assets/icons/forgejo.svg); }
.monitor-site-icon[src*="/tailscale.svg"] { -webkit-mask-image: url(/assets/icons/tailscale.svg); mask-image: url(/assets/icons/tailscale.svg); }
.monitor-site-icon[src*="/pihole.svg"] { -webkit-mask-image: url(/assets/icons/pihole.svg); mask-image: url(/assets/icons/pihole.svg); }
.monitor-site-icon[src*="/uptimekuma.svg"] { -webkit-mask-image: url(/assets/icons/uptimekuma.svg); mask-image: url(/assets/icons/uptimekuma.svg); }
.monitor-site-icon[src*="/vaultwarden.svg"] { -webkit-mask-image: url(/assets/icons/vaultwarden.svg); mask-image: url(/assets/icons/vaultwarden.svg); }
.monitor-site-icon[src*="/element.svg"] { -webkit-mask-image: url(/assets/icons/element.svg); mask-image: url(/assets/icons/element.svg); }

/* Ember keeps her face, and gets a tinted RING instead of being masked.
 *
 * The goal was colour consistency, and the ring achieves it from the same
 * var(--color-primary) as the masked glyphs — so she retints on a theme switch
 * and with every wallpaper, exactly like they do. What she does not do is stop
 * being recognisable, which is what a stencil costs a face.
 *
 * box-shadow rather than border: it draws OUTSIDE the box with no layout shift,
 * so nothing reflows and the 3.2rem sizing Glance sets is untouched. A border
 * would eat into the content box and shrink her.
 *
 * The glyph at /assets/icons/ember.svg is still present, still has its mask rule
 * above, and is one line in home.yml away. */
.monitor-site-icon[src$="ember.png"] {
  border-radius: 6px;
  filter: none;
  opacity: 1;
  box-shadow: 0 0 0 2px var(--color-primary);
  transition: box-shadow .3s;
}
