/* PP Mori from Rex's Pangram Pangram Font Starter Pack (the files Hey News serves): Regular for
   text, SemiBold as the headings' medium. */
@font-face { font-family: 'PP Mori'; src: url('../fonts/PPMori-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'PP Mori'; src: url('../fonts/PPMori-SemiBold.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; }

/* Shared by the directions. Beaux live on white (app D-048), so the page is true white. */
:root {
  color-scheme: light;
  --page: #ffffff;
  --ink: #1d1d1f;
  --ink-2: #5c5c61;  /* a touch darker than Apple's gray (Rex), 6.6:1 on white */
  --action: #1d1d1f;
  --action-hover: #2f6bff;
  --on-action: #ffffff;
  --card: #ffffff;
  --line: rgb(0 0 0 / 0.1);
  /* Light enough that text reads over it anywhere (Rex: lighter dots, no white behind text). */
  --dot: #f0f2f5;
  --glass: rgb(255 255 255 / 0.72);
  /* The system green the app's check uses (Color.green in light mode). */
  --copied: #34c759;
  /* The rainbow field behind glass and windows: each hue at its own lightness and its peak P3
     chroma, blended in OKLCH. Generated by rainbowGradient() in lib/rainbow.js; regenerate
     rather than edit. */
  /* The vivid rainbow, each hue at its own P3 peak (the mark's colors), drawn twice so it can
     drift in a loop: the glow behind the download button. Generated from vividCss() in
     lib/rainbow.js; regenerate rather than edit. */
  --rainbow-vivid: linear-gradient(90deg in oklch, oklch(0.671 0.290 0.0) 0.0%, oklch(0.655 0.278 30.0) 4.2%, oklch(0.771 0.196 60.0) 8.3%, oklch(0.800 0.179 90.0) 12.5%, oklch(0.800 0.210 120.0) 16.7%, oklch(0.800 0.292 150.0) 20.8%, oklch(0.800 0.187 180.0) 25.0%, oklch(0.800 0.175 210.0) 29.2%, oklch(0.680 0.193 240.0) 33.3%, oklch(0.477 0.299 270.0) 37.5%, oklch(0.559 0.295 300.0) 41.7%, oklch(0.713 0.338 330.0) 45.8%, oklch(0.671 0.290 0.0) 50.0%, oklch(0.655 0.278 30.0) 54.2%, oklch(0.771 0.196 60.0) 58.3%, oklch(0.800 0.179 90.0) 62.5%, oklch(0.800 0.210 120.0) 66.7%, oklch(0.800 0.292 150.0) 70.8%, oklch(0.800 0.187 180.0) 75.0%, oklch(0.800 0.175 210.0) 79.2%, oklch(0.680 0.193 240.0) 83.3%, oklch(0.477 0.299 270.0) 87.5%, oklch(0.559 0.295 300.0) 91.7%, oklch(0.713 0.338 330.0) 95.8%, oklch(0.671 0.290 0.0) 100.0%);
  --rainbow-field: linear-gradient(135deg in oklch, oklch(0.671 0.290 0.0) 0.0%, oklch(0.655 0.278 30.0) 9.1%, oklch(0.771 0.196 60.0) 18.2%, oklch(0.800 0.179 90.0) 27.3%, oklch(0.800 0.210 120.0) 36.4%, oklch(0.800 0.292 150.0) 45.5%, oklch(0.800 0.187 180.0) 54.5%, oklch(0.800 0.175 210.0) 63.6%, oklch(0.680 0.193 240.0) 72.7%, oklch(0.477 0.299 270.0) 81.8%, oklch(0.559 0.295 300.0) 90.9%, oklch(0.713 0.338 330.0) 100.0%);
  /* The desktop wallpaper on the MacBook that shows your history: Rex's background
     (2026-10-24), a hot pink field with four soft blobs, red-orange bottom left, pink bottom
     middle, indigo bottom right and navy top right, under a film grain. All four colors are his. */
  --block-pink: hsl(327 100% 50%);
  --block-orange: hsl(11 100% 50%);
  --block-indigo: hsl(236 100% 23%);
  --block-navy: hsl(206 100% 9%);
  --block-grain: url("data:image/svg+xml,%3Csvg viewBox='0 0 1111 1111' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
  /* How long the week row's tabs take to switch views. */
  --dur-switch: 450ms;
  --ease-switch: cubic-bezier(0.2, 0.7, 0.2, 1);
  /* One loop of the blobs' drift. */
  --band-cycle: 36s;

  /* Type (Rex, 2026-10-24, D-001): PP Mori throughout, Regular for text (Rex: "pp mori for
     body but regular not book") and SemiBold for the headings and the wordmark, served as the
     medium weight since Mori has no Medium cut (Rex: "maybe all h need to be medium"). Labels
     stay Regular. Hexes and data are in the system's
     monospaced font, SF Mono on Macs and iPhones as in the app, so there's nothing to download. The scale
     follows the Tailwind UI feature bento Rex pointed at: display sizes on tight leading,
     headings 20 on 28 slightly tight, reading text on 28-pixel leading, every heading medium,
     never bold. The hero and section sizes grow with the window. */
  --font-display: 'PP Mori', system-ui, -apple-system, sans-serif;
  --font-sans: 'PP Mori', system-ui, -apple-system, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', Menlo, monospace;
  /* The app's own faces, for the pictures of its windows, loupe and cards. */
  --font-app: system-ui, -apple-system, sans-serif;
  --font-app-mono: ui-monospace, 'SF Mono', Menlo, monospace;

  --text-hero-size: clamp(54px, 6vw + 16px, 93px);
  --text-hero-line: 1;
  --text-hero-weight: 500;
  --text-hero-track: -0.04em;

  --text-section-size: clamp(32px, 2vw + 16px, 48px);
  --text-section-line: 1.05;
  --text-section-weight: 500;
  --text-section-track: -0.03em;

  /* The big Bento tile's heading, between the section and the tile sizes. */
  --text-feature-size: 32px;
  --text-feature-line: 1.125;     /* 36 */
  --text-feature-weight: 500;
  --text-feature-track: -0.025em;

  --text-tile-size: 20px;
  --text-tile-line: 1.4;          /* 28 */
  --text-tile-weight: 500;
  --text-tile-track: -0.02em;

  --text-body-size: 18px;
  --text-body-line: 1.5556;       /* 28 */
  --text-body-weight: 400;
  --text-body-track: 0;

  --text-small-size: 16px;
  --text-small-line: 1.75;        /* 28 */
  --text-small-weight: 400;
  --text-small-track: 0;

  --text-label-size: 13px;
  --text-label-line: 1.5385;      /* 20 */
  --text-label-weight: 400;
  --text-label-track: 0.01em;

  /* Reading text never runs wider than this. */
  --measure: 60ch;

  /* The app's macOS text styles in points, for the pictures of its loupe and cards only. */
  --mac-title-size: 22px;
  --mac-title2-size: 17px;
  --mac-title3-size: 15px;
  --mac-body-size: 13px;
  --mac-callout-size: 12px;
  --mac-line: 1.25;
  --mac-semibold: 600;

  /* Spacing on the 8-point grid, named by eighths as the house library names them. */
  --sp-1: 8px; --sp-2: 16px; --sp-3: 24px; --sp-4: 32px;
  --sp-5: 40px; --sp-6: 48px; --sp-8: 64px; --sp-12: 96px; --sp-16: 128px;
  /* The gaps by what they hold together, closest first. */
  --gap-tile-head: var(--sp-1);  /* a tile's heading to its line */
  --gap-head: var(--sp-2);       /* a heading to its line */
  --gap-tile-art: var(--sp-3);   /* a tile's line to its art */
  --pad-card: var(--sp-3);       /* inside a glass card */
  --gap-art: var(--sp-6);        /* a line to the art or button under it; a beau standing on
                                    the art is 48 tall, so nothing closer */
  --gap-tiles: var(--sp-3);      /* between tiles side by side */
  --gap-tile-rows: var(--sp-8);  /* between stacked tiles, room for beaux on the lower top */
  --gap-section: var(--sp-16);   /* between sections */
  --pad-band: var(--sp-12);      /* inside a full-bleed band, top and bottom */
  --gutter: var(--sp-4);         /* the page's sides */
}

@media (max-width: 600px) { :root { --gutter: var(--sp-2); } }

* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-body-size); line-height: var(--text-body-line); font-weight: var(--text-body-weight);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

/* Headings and the wordmark in the display face (PP Mori, as the text). */
h1, h2, h3, .wordmark { font-family: var(--font-display); }

.wordmark { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--text-tile-size); line-height: 1; font-weight: var(--text-tile-weight); letter-spacing: var(--text-tile-track); text-decoration: none; }
.mark { display: block; }

.download {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3); border-radius: 12px;
  background: var(--action); color: var(--on-action);
  font-family: var(--font-sans); font-size: var(--text-body-size); line-height: 1; font-weight: var(--text-tile-weight); text-decoration: none;
  transition: background-color 0.15s ease;
}
.download svg { width: 16px; height: 16px; }
.get-meta { font-size: var(--text-label-size); line-height: var(--text-label-line); font-weight: var(--text-label-weight); letter-spacing: var(--text-label-track); color: var(--ink-2); }
.link { text-decoration: none; }
/* A link on its own line is at least 24 tall, the smallest target WCAG 2.2 allows. */
.foot .link { display: inline-block; min-height: var(--sp-3); padding: 2px 0; }
/* Rex's hand-drawn FREE in place of the word, in the hero's summary and the foot's line (Rex,
   2026-10-24). It sits in the line like a word, a little taller than the text so the burst reads,
   and its label keeps the sentence whole for screen readers. The drawing (lib/free.svg) is a mask
   over a color that drifts slowly round the rainbow, a hue every three seconds (Rex: "could the
   free slowly transition into other colors of the rainbow that will work on white?"). Each hue
   is as light and saturated as white allows at 4.6:1 or better, the blends between them
   included, on P3 and sRGB screens. Still on the red under Reduce Motion. */
.free { display: inline-block; height: 1.5em; width: calc(1.5em * 51 / 30); margin: -0.35em 0.1em -0.25em; vertical-align: middle;
  background-color: oklch(0.584 0.253 0);
  -webkit-mask: url(free.svg) center / contain no-repeat; mask: url(free.svg) center / contain no-repeat;
  animation: free-hue 36s linear infinite; }
@keyframes free-hue {
  0.0% { background-color: oklch(0.584 0.253 0); }
  8.33% { background-color: oklch(0.585 0.25 30); }
  16.67% { background-color: oklch(0.572 0.146 60); }
  25.0% { background-color: oklch(0.563 0.126 90); }
  33.33% { background-color: oklch(0.553 0.146 120); }
  41.67% { background-color: oklch(0.531 0.194 150); }
  50.0% { background-color: oklch(0.537 0.125 180); }
  58.33% { background-color: oklch(0.542 0.119 210); }
  66.67% { background-color: oklch(0.551 0.157 240); }
  75.0% { background-color: oklch(0.579 0.234 270); }
  83.33% { background-color: oklch(0.596 0.267 300); }
  91.67% { background-color: oklch(0.593 0.281 330); }
  100% { background-color: oklch(0.584 0.253 0); }
}
@media (prefers-reduced-motion: reduce) { .free { animation: none; } }
/* The foot's last line, under the beaux (Rex: "put the made by and privacy under the beaux at the
   bottom"): who made it on the left, Privacy on the right. The space above it is the beaux's: they
   walk on a floor 40 over this line (Rex: "give like 40px between beaux and footer elements";
   lib/home.js, lib/privacy.js), with 128 above the floor for a beau, its emote and the caption that
   floats over it, so the caption clears the free line. */
.foot-row { --beaux-gap: var(--sp-5); display: flex; justify-content: space-between; gap: var(--sp-2); margin-top: calc(var(--sp-16) + var(--beaux-gap)); text-align: left; }

@media (hover: hover) and (pointer: fine) {
  .link:hover { color: var(--action-hover); }
}

/* The beaux layer: one canvas over everything, never in the way of a click. */
canvas.beaux { position: fixed; inset: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 10; }
/* Over a walking beau the mouse becomes an eyedropper (after the app's Pick row symbol, with a
   white outline so it reads on any color), its hotspot at the tip; a crosshair if it can't load. */
html.beau-over, html.beau-over * { cursor: url(eyedropper.svg) 2 22, crosshair; }

/* The story line over the beaux it names. */
.beau-caption {
  position: fixed; left: 0; top: 0; z-index: 13; pointer-events: none; opacity: 0;
  font-size: var(--text-label-size); font-weight: var(--text-label-weight); letter-spacing: var(--text-label-track); color: var(--ink-2); white-space: nowrap;
}

/* A light dot grid on the page: a 1px dot every 24px, on the 8-point grid, in a cool gray. */
.dotted { background-color: var(--page); background-image: radial-gradient(circle at 12px 12px, var(--dot) 1px, transparent 1.6px); background-size: 24px 24px; }

/* rainbo's loupe and its card (lib/loupe.js), over a beau you point at. The loupe and card copy
   the app's LensView and PickCard, in the system font the app uses. */
.pick-loupe { position: fixed; left: 0; top: 0; z-index: 15; opacity: 0; width: 120px; height: 120px; border-radius: 50%; overflow: hidden; pointer-events: none;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 40%, transparent), 0 4px 16px color-mix(in srgb, var(--ink) 20%, transparent); }
.pick-loupe canvas { display: block; width: 120px; height: 120px; image-rendering: pixelated; }
.pick-ring { position: absolute; left: 56px; top: 56px; width: 6px; height: 6px; border: 1px solid var(--page); outline: 2px solid var(--ink); }
.pick-loupe.on, .pick-card.on { opacity: 1; }
/* An open card takes clicks on its hex, which copies. */
.pick-card.open.on { pointer-events: auto; }
.pick-card.open .pick-hexline { cursor: pointer; }
.pick-card { position: fixed; left: 0; top: 0; z-index: 15; opacity: 0; width: 224px; padding: 12px; border-radius: 12px; pointer-events: none; text-align: left;
  display: flex; flex-direction: column; gap: 12px; font: var(--mac-body-size)/var(--mac-line) var(--font-app); color: var(--ink);
  background: var(--glass); -webkit-backdrop-filter: blur(24px) saturate(1.6); backdrop-filter: blur(24px) saturate(1.6);
  box-shadow: inset 0 0 0 0.5px color-mix(in srgb, var(--page) 80%, transparent), 0 0 0 0.5px var(--line), 0 12px 40px color-mix(in srgb, var(--ink) 16%, transparent); }
.pick-head { display: flex; gap: 12px; align-items: center; }
.pick-head > span:last-child { display: flex; flex-direction: column; gap: 2px; }
.pick-swatch { width: 40px; height: 40px; border-radius: 6px; flex: none; box-shadow: inset 0 0 0 1px var(--line); }
.pick-hex { font: var(--mac-semibold) var(--mac-title2-size) var(--font-app-mono); }
.pick-hexline { display: flex; align-items: center; gap: 4px; }
.pick-name { font-size: var(--mac-callout-size); color: var(--ink-2); }
.pick-tiles { display: flex; gap: 8px; }
.pick-tile { flex: 1; padding: 8px; border-radius: 8px; box-shadow: inset 0 0 0 1px var(--line); display: flex; flex-direction: column; gap: 2px; font-size: var(--mac-callout-size); font-variant-numeric: tabular-nums; }
.pick-aa { font-size: var(--mac-title-size); font-weight: var(--mac-semibold); line-height: 1.1; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* Glass, as the app's History strip floats on Liquid Glass: a translucent fill over a blur, a
   thin light edge, 24-point corners. The card row's panel and the section cards share it. */
.glass-panel { padding: var(--pad-card); border-radius: 24px; background: var(--glass);
  -webkit-backdrop-filter: blur(24px) saturate(1.6); backdrop-filter: blur(24px) saturate(1.6);
  box-shadow: inset 0 0 0 0.5px color-mix(in srgb, var(--page) 80%, transparent), 0 0 0 0.5px var(--line), 0 16px 48px color-mix(in srgb, var(--ink) 10%, transparent); }

/* The card row (lib/card-panel.js): the app's History strip cards, a quarter larger, in a row
   that scrolls sideways inside the glass's 24 of padding, with no scrollbar showing. The cards
   stay opaque white on the glass. The glass sits on the rainbow, as the History strip sits over
   whatever is on your screen, so it reads as glass: a light translucent fill (30%), a strong
   blur, a bright top edge and a faint lower one, and no drop shadow. No saturation boost, so the
   text contrast measured against the field holds. */
.panel-glass { padding: var(--pad-card); border-radius: 24px; background: color-mix(in srgb, var(--page) 30%, transparent);
  -webkit-backdrop-filter: blur(32px); backdrop-filter: blur(32px);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--page) 90%, transparent), inset 0 -1px 0 color-mix(in srgb, var(--ink) 10%, transparent),
    inset 0 0 0 0.5px color-mix(in srgb, var(--page) 40%, transparent); }
.panel { width: 100%; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; overscroll-behavior-x: contain; cursor: grab; outline-offset: 4px; border-radius: 18px; }
.panel::-webkit-scrollbar { display: none; }
.panel.dragging { cursor: grabbing; user-select: none; }
.panel-track { display: flex; gap: var(--sp-3); width: max-content; }
.panel-day { display: flex; gap: var(--sp-1); }
.panel-card { width: 240px; height: 270px; flex: none; display: flex; flex-direction: column; background: var(--card); border-radius: 18px; overflow: hidden;
  box-shadow: inset 0 0 0 0.5px var(--line);
  font: var(--mac-body-size)/var(--mac-line) var(--font-app); color: var(--ink); text-align: left; }
.panel-chip { height: 150px; box-shadow: inset 0 0 0 1px var(--line); }
.panel-meta { padding: var(--sp-2); display: flex; flex-direction: column; gap: 2px; }
.panel-name { font-size: var(--mac-title3-size); font-weight: var(--mac-semibold); }
.panel-hex { font: var(--mac-callout-size) var(--font-app-mono); }
.panel-when { margin-top: auto; padding: 0 var(--sp-2) var(--sp-2); font-size: var(--mac-callout-size); color: var(--ink-2); }

/* The copy mark beside a hex (lib/copy-mark.js): gray while hovered, a green check once copied. */
.copy-mark { display: inline-flex; width: 18px; height: 18px; align-items: center; justify-content: center; vertical-align: middle;
  color: var(--ink-2); opacity: 0; transition: opacity 0.15s ease-out; }
.copy-mark svg { width: 13px; height: 13px; }
.copy-mark.shown, .copy-mark.copied { opacity: 1; }
.copy-mark.copied { color: var(--copied); }



/* The download button's hover: a rainbow glow behind it (Rex: "it glows behind the button on
   hover ... a rainbow"). The button keeps its dark fill and white label; behind it the vivid rainbow,
   blurred, fades in and drifts, one loop every 4 seconds. The glow sits under the button, so the
   colors can be at full strength without touching the label's contrast. Hover-capable pointers
   only; still under Reduce Motion. */
.download { position: relative; transition: background-color 0.15s ease; }
.download::before { content: ''; position: absolute; inset: -6px; z-index: -1; border-radius: 18px; pointer-events: none;
  background: var(--rainbow-vivid); background-size: 200% 100%; filter: blur(16px); opacity: 0; transition: opacity 0.3s ease-out; }
@media (hover: hover) and (pointer: fine) {
  .download:not(.download-soon):hover::before { opacity: 1; animation: download-glow 4s linear infinite; }
}
@keyframes download-glow { to { background-position: 100% 0; } }
@media (prefers-reduced-motion: reduce) { .download:hover::before { animation: none; } }
/* Until the app ships, the download buttons say Coming soon (Rex: "just make the download button
   not active? change it to coming soon"): not a link and no pointer, the same size as the button
   it stands in for so nothing moves. It's a white button with the rainbow glowing behind it all
   the time, not only on hover (Rex: "make it a white button background with the rainbow behind
   it without hover"); the label is ink on white. Screen readers hear "Download, coming soon".
   When the app is out, they go back to links to rainbo.zip. */
.download-soon { justify-content: center; min-width: 12.75em; background: var(--card); color: var(--ink); cursor: default; }
.download-soon::before { opacity: 1; animation: download-glow 4s linear infinite; }
@media (prefers-reduced-motion: reduce) { .download-soon::before { animation: none; } }

/* One beau large with its name and hex (lib/beau-spec.js). The art area grows with the tile and
   the beau is sized to fill it; a click on it swaps in another beau. */
.beau-spec { margin-top: var(--gap-tile-art); display: flex; flex-direction: column; gap: var(--sp-2); }
.beau-spec-stage { position: relative; flex: 1; min-height: 160px; display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; border-radius: 12px; }
.beau-spec-art { position: absolute; inset: 0; display: block; image-rendering: pixelated; transition: opacity 150ms ease-out; }
.beau-spec-art.fading { opacity: 0; }
.beau-spec-codes { display: flex; flex-direction: column; color: var(--ink); }
.beau-spec-name { font-size: var(--text-small-size); line-height: var(--text-small-line); font-weight: var(--text-tile-weight); }
.beau-spec-hex { align-self: flex-start; display: inline-flex; align-items: center; gap: 4px; min-height: var(--sp-3); padding: 0; border: 0; background: none; cursor: pointer;
  font: var(--text-body-weight) var(--text-label-size)/var(--text-label-line) var(--font-mono); color: var(--ink); }
@media (hover: hover) and (pointer: fine) { .beau-spec-hex:hover { color: var(--action-hover); } }

/* A month's top colors, as the app's Recaps draws them (TopColors.swift): a bar split by share,
   then a swatch and name for each, small and quiet. */
/* The bar grows to fill the tile's art area, a tall block of the month's colors. */
.top-colors { flex: 1; display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--gap-tile-art); }
.share-bar { flex: 1; min-height: var(--sp-6); display: flex; border-radius: 12px; overflow: hidden; box-shadow: inset 0 0 0 1px var(--line); }
.share-bar i { display: block; }
.share-labels { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2); font-size: var(--text-label-size); line-height: var(--text-label-line); font-weight: var(--text-label-weight); letter-spacing: var(--text-label-track); color: var(--ink-2); }
.share-labels span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.share-labels i { width: 8px; height: 8px; display: block; box-shadow: inset 0 0 0 1px var(--line); }

/* The MacBook's wallpaper (lib/band.js). The field and its four blobs sit on ::before; each blob's center
   drifts on its own gentle loop, its x and y swinging a quarter turn apart, so the loop is a soft
   ellipse, a full one every --band-cycle, the four starting at different points of it. The grain
   sits on ::after, blended as overlay. Held still under Reduce Motion, paused off screen and in a
   hidden tab. */
@property --blob-ox { syntax: '<percentage>'; inherits: false; initial-value: 0%; }
@property --blob-oy { syntax: '<percentage>'; inherits: false; initial-value: 99%; }
@property --blob-px { syntax: '<percentage>'; inherits: false; initial-value: 46%; }
@property --blob-py { syntax: '<percentage>'; inherits: false; initial-value: 94%; }
@property --blob-ix { syntax: '<percentage>'; inherits: false; initial-value: 93%; }
@property --blob-iy { syntax: '<percentage>'; inherits: false; initial-value: 95%; }
@property --blob-nx { syntax: '<percentage>'; inherits: false; initial-value: 89%; }
@property --blob-ny { syntax: '<percentage>'; inherits: false; initial-value: 8%; }
.band { position: relative; overflow: hidden; isolation: isolate; }
.band::before, .band::after { content: ''; position: absolute; inset: 0; pointer-events: none; }
.band::before { z-index: -2; background-color: var(--block-pink);
  background-image: radial-gradient(circle at var(--blob-ox) var(--blob-oy), var(--block-orange) 0%, transparent 67%),
    radial-gradient(circle at var(--blob-px) var(--blob-py), var(--block-pink) 0%, transparent 81%),
    radial-gradient(circle at var(--blob-ix) var(--blob-iy), var(--block-indigo) 0%, transparent 66%),
    radial-gradient(circle at var(--blob-nx) var(--blob-ny), var(--block-navy) 0%, transparent 150%);
  --half: calc(var(--band-cycle) / 2);
  animation: blob-ox var(--half) ease-in-out 0s infinite alternate, blob-oy var(--half) ease-in-out calc(var(--half) / -2) infinite alternate,
    blob-px var(--half) ease-in-out calc(var(--half) / -4) infinite alternate, blob-py var(--half) ease-in-out calc(var(--half) * -0.75) infinite alternate,
    blob-ix var(--half) ease-in-out calc(var(--half) / -2) infinite alternate, blob-iy var(--half) ease-in-out calc(var(--half) * -1) infinite alternate,
    blob-nx var(--half) ease-in-out calc(var(--half) * -0.75) infinite alternate, blob-ny var(--half) ease-in-out calc(var(--half) * -1.25) infinite alternate; }
@keyframes blob-ox { to { --blob-ox: 12%; } }
@keyframes blob-oy { to { --blob-oy: 84%; } }
@keyframes blob-px { to { --blob-px: 60%; } }
@keyframes blob-py { to { --blob-py: 80%; } }
@keyframes blob-ix { to { --blob-ix: 78%; } }
@keyframes blob-iy { to { --blob-iy: 82%; } }
@keyframes blob-nx { to { --blob-nx: 72%; } }
@keyframes blob-ny { to { --blob-ny: 22%; } }
.band::after { z-index: -1; background-image: var(--block-grain); mix-blend-mode: overlay; }
.band.band-paused::before { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .band::before { animation: none; } }

/* A MacBook Pro 14-inch, Apple's product bezel (Bezel-MacBook-Pro-M5, Apple Design Resources),
   with a desktop drawn in its screen (lib/macbook.js). The bezel image is 3860 by 2540 with its
   screen at 418, 288, 3024 wide and 1964 tall, a 1512 by 982 point display; the desktop is drawn
   at those points and scaled to fit, and the bezel sits over it so its notch and rounded corners
   cut the desktop as the real screen does. The box's top is the lid's top edge (the image has 233
   pixels of clear space above it), so beaux stand on the lid. */
.macbook { position: relative; width: 100%; aspect-ratio: 3860 / 2307; }
.macbook-frame { position: absolute; left: 0; top: -10.1%; width: 100%; height: auto; pointer-events: none; z-index: 1; }
.macbook-screen { position: absolute; left: 10.829%; top: calc(-10.1% + 11.339% * 2540 / 2307); width: 78.342%; aspect-ratio: 3024 / 1964; overflow: hidden; }
.macbook-desktop { position: absolute; left: 0; top: 0; width: 1512px; height: 982px; transform-origin: 0 0; }
/* The two views. The strip docks along the desktop's bottom and slides down out of sight when the
   other view is chosen, as it does in the app; the History window fades and settles in. */
.scene { position: absolute; transition: opacity var(--dur-switch) var(--ease-switch), transform var(--dur-switch) var(--ease-switch); }
.scene:not(.is-active) { opacity: 0; pointer-events: none; }
.scene-strip { left: 24px; right: 24px; bottom: 24px; }
.scene-strip .panel-glass { zoom: 0.8; }
.scene-strip:not(.is-active) { transform: translateY(120%); }
.scene-window { left: 136px; top: 72px; }
.scene-window:not(.is-active) { transform: translateY(24px) scale(0.97); }
.scene-window .shot { width: 1240px; height: 840px; aspect-ratio: auto !important; overflow: visible; background: none; box-shadow: none; border-radius: 0; }
.scene-window .shot > .native { background: none !important; }
.scene-window .mac .window { left: 0; top: 0; }
@media (prefers-reduced-motion: reduce) { .scene:not(.is-active) { transform: none; } }
