@font-face {
  font-family: 'Fraunces';
  src: url('../fonts/fraunces.woff2') format('woff2');
  font-weight: 100 900;
  font-display: block;
}
@font-face {
  font-family: 'Atkinson';
  src: url('../fonts/atkinson.woff2') format('woff2');
  font-weight: 200 800;
  font-display: block;
}

/* Scenery colours are set from app.js for the time of day; these are the night values. */
:root {
  --sky-top: #03051a;
  --sky-mid: #0a1334;
  --sky-low: #1b2a58;
  --floor: #03040b;
  --cloud-lit: rgba(170, 190, 255, 0.07);
  --cloud-shade: rgba(0, 0, 0, 0.1);
  --haze: rgba(120, 140, 255, 0.1);
  --glare: #dfe6ff;
  --rays: 0;
  --flare: 0;
  --rim: 0.08;
  --aurora: 1;
  --fireflies: 0.7;
  --mist: 0.2;
  --godrays: 0;
  --pines: #020308;
  --stars: 1;
  --milky: 1;
  --ridge-far: #16234a;
  --ridge-mid: #0d1530;
  --ridge-near: #060a19;
  --lake-top: #0c1430;
  --lake-glow: rgba(200, 210, 255, 0.12);
  --paper: #f6f1ea;
  --muted: rgba(246, 241, 234, 0.7);
  --faint: rgba(246, 241, 234, 0.42);
  --edge: 112px;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--floor);
}

body {
  font-family: 'Atkinson', sans-serif;
  color: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* Always laid out at the TV's 1920x1080; app.js scales it down to fit a smaller preview window. */
.screen {
  position: relative;
  width: 1920px;
  height: 1080px;
  overflow: hidden;
  transform-origin: 0 0;
  background: var(--floor);
}

/* ---- Scenery ------------------------------------------------------------------------------ */

/* Its own layer, so moving tiles and text never make the TV repaint the landscape. */
.sky {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
  will-change: transform;
  background: linear-gradient(180deg,
    var(--sky-top) 0%,
    var(--sky-mid) 24%,
    var(--sky-low) 44%,
    var(--floor) 64%);
}

.milkyway {
  position: absolute;
  left: -10%;
  top: -24%;
  width: 120%;
  height: 70%;
  opacity: var(--milky);
  transform: rotate(-16deg);
  background:
    radial-gradient(ellipse 46% 15% at 50% 52%, rgba(196, 206, 255, 0.11), transparent 72%),
    radial-gradient(ellipse 26% 7% at 44% 54%, rgba(255, 236, 226, 0.08), transparent 72%),
    radial-gradient(ellipse 18% 5% at 63% 49%, rgba(206, 222, 255, 0.07), transparent 72%),
    radial-gradient(ellipse 10% 3% at 52% 51%, rgba(10, 12, 30, 0.35), transparent 72%);
}

.stars {
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  opacity: var(--stars);
}

.twinkles { position: absolute; top: 0; right: 0; bottom: 0; left: 0; opacity: var(--stars); }
.twinkles i {
  position: absolute;
  width: 3px;
  height: 3px;
  margin: -1.5px 0 0 -1.5px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 6px 2px rgba(220, 230, 255, 0.55);
}
.is-night .twinkles i { animation: twinkle var(--t, 4s) ease-in-out infinite alternate; }

/* Clouds drift so slowly that you only notice they have moved, never that they are moving. */
.clouds {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -3%;
  right: -3%;
  will-change: transform;
}
.clouds--wisps { animation: cloud-drift 260s ease-in-out infinite alternate; }
.clouds--puffs { animation: cloud-drift 340s ease-in-out -120s infinite alternate-reverse; }

.clouds--wisps {
  background:
    radial-gradient(ellipse 520px 34px at 26% 17%, var(--cloud-lit), transparent 72%),
    radial-gradient(ellipse 340px 22px at 33% 19.5%, var(--cloud-lit), transparent 72%),
    radial-gradient(ellipse 640px 40px at 63% 9%, var(--cloud-lit), transparent 72%),
    radial-gradient(ellipse 420px 26px at 71% 12%, var(--cloud-lit), transparent 72%),
    radial-gradient(ellipse 560px 30px at 90% 21%, var(--cloud-lit), transparent 72%);
}

/* Three cumulus banks: bright tops, cooler shaded bases. */
.clouds--puffs {
  background:
    radial-gradient(ellipse 110px 54px at 43% 25%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 150px 70px at 46.5% 23%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 120px 58px at 50.5% 24.5%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 90px 44px at 53.5% 26.5%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 300px 48px at 48% 29%, var(--cloud-shade), transparent 72%),
    radial-gradient(ellipse 90px 46px at 7% 33%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 130px 60px at 10.5% 31.5%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 100px 48px at 14% 33.5%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 240px 40px at 11% 36.5%, var(--cloud-shade), transparent 72%),
    radial-gradient(ellipse 100px 48px at 76% 34%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 140px 62px at 79.5% 32.5%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 110px 50px at 83% 34.5%, var(--cloud-lit), transparent 70%),
    radial-gradient(ellipse 270px 42px at 80% 37.5%, var(--cloud-shade), transparent 72%);
}

/* Light on the horizon below the sun or moon. */
.haze {
  position: absolute;
  left: 0;
  top: 0;
  width: 1600px;
  height: 520px;
  margin: -260px 0 0 -800px;
  background: radial-gradient(closest-side, var(--haze), transparent);
}

/* The sun and everything it does to the lens. Positioned from app.js. */
.glare {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  opacity: 0;
  transition: opacity 900ms linear;
}
.glare.is-up { opacity: 1; }

.glare > * { position: absolute; left: 0; top: 0; border-radius: 50%; }

.glare-rays {
  width: 1240px;
  height: 1240px;
  margin: -620px 0 0 -620px;
  opacity: var(--rays);
  background: repeating-conic-gradient(from 4deg,
    rgba(255, 255, 255, 0) 0deg 5deg,
    var(--glare) 6.5deg,
    rgba(255, 255, 255, 0) 8deg 13deg);
  -webkit-mask-image: radial-gradient(circle, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.22) 22%, transparent 58%);
  mask-image: radial-gradient(circle, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.22) 22%, transparent 58%);
}
.glare-rays { animation: turn 260s linear infinite; will-change: transform; }
.glare-rays--fine {
  width: 860px;
  height: 860px;
  margin: -430px 0 0 -430px;
  animation: turn 190s linear infinite reverse;
  background: repeating-conic-gradient(from 0deg,
    rgba(255, 255, 255, 0) 0deg 2deg,
    var(--glare) 2.6deg,
    rgba(255, 255, 255, 0) 3.2deg 7.4deg);
}

.glare-halo {
  width: 820px;
  height: 820px;
  margin: -410px 0 0 -410px;
  animation: breathe 7s ease-in-out infinite alternate;
  will-change: transform, opacity;
  background: radial-gradient(circle,
    rgba(255, 246, 228, 0.62) 0%,
    rgba(255, 226, 170, 0.34) 9%,
    rgba(255, 200, 130, 0.14) 24%,
    rgba(255, 190, 120, 0.05) 42%,
    transparent 66%);
}

/* The faint 22-degree ring around a bright sun, warm inside and cool outside. */
.glare-ring {
  width: 600px;
  height: 600px;
  margin: -300px 0 0 -300px;
  opacity: var(--rays);
  background: radial-gradient(circle,
    transparent 63%,
    rgba(255, 210, 160, 0.1) 66%,
    rgba(255, 255, 230, 0.08) 68%,
    rgba(170, 220, 255, 0.07) 70%,
    transparent 73%);
}

.sun {
  width: 116px;
  height: 116px;
  margin: -58px 0 0 -58px;
  background: radial-gradient(circle at 50% 50%, #fffdf7 0%, #fff5dc 46%, #ffe0a2 76%, #ffd18a 100%);
  box-shadow: 0 0 34px 10px rgba(255, 236, 196, 0.7);
}

/* The anamorphic streak a camera lens draws through a low sun. */
.glare-streak {
  width: 1700px;
  height: 22px;
  margin: -11px 0 0 -850px;
  border-radius: 50%;
  opacity: var(--flare);
  background: radial-gradient(ellipse 50% 50% at 50% 50%,
    rgba(255, 250, 238, 0.7) 0%,
    rgba(255, 220, 170, 0.22) 22%,
    rgba(255, 200, 150, 0.06) 55%,
    transparent 72%);
}

.moon {
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
  transition: opacity 900ms linear;
}
.moon.is-up { opacity: 1; }

.moon-glow {
  position: absolute;
  width: 520px;
  height: 520px;
  margin: -260px 0 0 -260px;
  border-radius: 50%;
  animation: breathe 9s ease-in-out infinite alternate;
  will-change: transform, opacity;
  background: radial-gradient(circle,
    rgba(220, 228, 255, 0.24) 0%,
    rgba(200, 214, 255, 0.09) 18%,
    transparent 46%,
    rgba(210, 222, 255, 0.05) 55%,
    transparent 60%);
}

/* The disc: soft maria (the dark "seas") drawn with gradients, then the phase shadow over it. */
.moon-disc {
  position: absolute;
  width: 100px;
  height: 100px;
  margin: -50px 0 0 -50px;
  border-radius: 50%;
  overflow: hidden;
  background:
    radial-gradient(circle at 34% 30%, rgba(150, 146, 132, 0.45) 0%, transparent 15%),
    radial-gradient(circle at 58% 42%, rgba(150, 146, 132, 0.4) 0%, transparent 17%),
    radial-gradient(circle at 44% 62%, rgba(150, 146, 132, 0.32) 0%, transparent 13%),
    radial-gradient(circle at 70% 66%, rgba(150, 146, 132, 0.28) 0%, transparent 10%),
    radial-gradient(circle at 26% 54%, rgba(150, 146, 132, 0.24) 0%, transparent 8%),
    radial-gradient(circle at 40% 36%, #fdfbf3 0%, #ece7d8 58%, #d2cbb8 100%);
  box-shadow: 0 0 26px 6px rgba(220, 228, 255, 0.3);
}

.moon-shade {
  position: absolute;
  top: -1px;
  right: -1px;
  bottom: -1px;
  left: -1px;
  border-radius: 50%;
  background: var(--sky-mid);
  opacity: 0.93;
}

/* Birds and the occasional shooting star; app.js sends them across now and then. */
.birds {
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
}
.birds path {
  fill: none;
  stroke: rgba(20, 24, 40, 0.62);
  stroke-width: 2.2;
  stroke-linecap: round;
}
.birds.is-flying { animation: fly var(--fly-time, 36s) linear 1 forwards; }

.meteor {
  position: absolute;
  left: 0;
  top: 0;
  width: 220px;
  height: 2px;
  border-radius: 1px;
  opacity: 0;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(235, 240, 255, 0.95));
  transform-origin: 100% 50%;
}
.meteor.is-falling { animation: fall 1100ms ease-in 1 forwards; }

/* The lake: the sky's colours mirrored and darkened, with the sun or moon's reflection. */
.lake {
  position: absolute;
  left: 0;
  right: 0;
  top: 516px;
  bottom: 0;
  background:
    radial-gradient(ellipse 22% 9% at var(--refl-x, 80%) 0%, var(--lake-glow), transparent 70%),
    radial-gradient(ellipse 48% 22% at var(--refl-x, 80%) 0%, var(--haze), transparent 72%),
    linear-gradient(180deg, var(--lake-top) 0%, var(--floor) 46%);
}

/* The path of light on the water: two random dash textures crossfading make it shimmer. */
.glitter {
  position: absolute;
  left: 0;
  top: 518px;
  width: 360px;
  height: 330px;
  margin-left: -180px;
  opacity: 0;
  transition: opacity 900ms linear;
  -webkit-mask-image: radial-gradient(ellipse 50% 100% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.55) 34%, transparent 76%);
  mask-image: radial-gradient(ellipse 50% 100% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.55) 34%, transparent 76%);
}
.glitter.is-on { opacity: 1; }
.glitter-layer { position: absolute; top: 0; right: 0; bottom: 0; left: 0; animation: sway 9s ease-in-out infinite alternate; }
.glitter-layer--alt { animation: shimmer 2.8s ease-in-out infinite alternate; }

/* Ripples spreading on the open water, now and then. */
.ripple {
  position: absolute;
  width: 220px;
  height: 70px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  opacity: 0;
  animation: ripple 7s ease-out infinite;
  will-change: transform, opacity;
}
.ripple--two { animation-delay: 3.5s; }

/* Once the scenery is in place, the sun, moon and their light glide between the positions set
   each minute instead of hopping. */
.is-live .glare { transition: opacity 900ms linear, transform 58s linear; }
.is-live .moon { transition: opacity 900ms linear, transform 58s linear; }
.is-live .haze, .is-live .glitter, .is-live .column, .is-live .godrays { transition: transform 58s linear, opacity 900ms linear; }

.ridges {
  position: absolute;
  left: 0;
  top: 360px;
  width: 1920px;
  height: 160px;
}
/* The light catches the ridgelines, most at sunrise and sunset. */
.ridge--far { fill: var(--ridge-far); stroke: var(--glare); stroke-opacity: var(--rim); stroke-width: 1.6; }
.ridge--mid { fill: var(--ridge-mid); stroke: var(--glare); stroke-opacity: calc(var(--rim) * 0.6); stroke-width: 1.2; }
.ridge--near { fill: var(--ridge-near); }

.ridges--reflection {
  top: 516px;
  opacity: 0.5;
  transform: scaleY(-1);
  -webkit-mask-image: linear-gradient(0deg, #000 0%, rgba(0, 0, 0, 0.4) 45%, transparent 100%);
  mask-image: linear-gradient(0deg, #000 0%, rgba(0, 0, 0, 0.4) 45%, transparent 100%);
}

/* Lens ghosts strung along the line from the sun through the centre of the screen. */
.flares { position: absolute; top: 0; right: 0; bottom: 0; left: 0; opacity: var(--flare); }
.flares i { position: absolute; left: 0; top: 0; border-radius: 50%; }
.flares .hex { border-radius: 0; clip-path: polygon(25% 4%, 75% 4%, 100% 50%, 75% 96%, 25% 96%, 0 50%); }

/* Fine noise over the gradients so the TV panel doesn't show colour bands. */
.grain {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  opacity: 0.035;
}

/* ---- The newer layers ---- */

/* Aurora: two soft curtains that drift very slowly. Only transforms animate, and only at night. */
.aurora {
  position: absolute;
  left: -12%;
  top: -6%;
  width: 124%;
  height: 58%;
  opacity: 0;
  background: linear-gradient(104deg,
    rgba(0, 0, 0, 0) 8%,
    rgba(86, 255, 196, 0.30) 26%,
    rgba(120, 140, 255, 0.26) 44%,
    rgba(70, 230, 255, 0.22) 58%,
    rgba(190, 120, 255, 0.18) 70%,
    rgba(0, 0, 0, 0) 88%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 55%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 55%, transparent 100%);
  will-change: transform;
}
.aurora--two {
  top: 2%;
  height: 46%;
  background: linear-gradient(96deg,
    rgba(0, 0, 0, 0) 14%,
    rgba(150, 110, 255, 0.22) 36%,
    rgba(80, 255, 210, 0.24) 52%,
    rgba(0, 0, 0, 0) 80%);
}
.has-aurora .aurora { opacity: var(--aurora); }
.has-aurora .aurora--one { animation: aurora-drift 70s ease-in-out infinite alternate; }
.has-aurora .aurora--two { animation: aurora-drift 95s ease-in-out -30s infinite alternate-reverse; }

/* Broad beams fanning out from a low sun through the clouds. */
.godrays {
  position: absolute;
  left: 0;
  top: 0;
  width: 2400px;
  height: 2400px;
  margin: -1200px 0 0 -1200px;
  border-radius: 50%;
  opacity: var(--godrays);
  background: repeating-conic-gradient(from 150deg,
    rgba(255, 236, 200, 0) 0deg 9deg,
    rgba(255, 236, 200, 0.14) 13deg,
    rgba(255, 236, 200, 0) 17deg 31deg);
  -webkit-mask-image: radial-gradient(circle, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.35) 30%, transparent 58%);
  mask-image: radial-gradient(circle, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.35) 30%, transparent 58%);
}

/* A column of light on the water beneath the sun or moon. */
.column {
  position: absolute;
  left: 0;
  top: 518px;
  width: 220px;
  height: 320px;
  margin-left: -110px;
  opacity: 0;
  background: linear-gradient(180deg, var(--column, rgba(255, 255, 255, 0.15)) 0%, rgba(255, 255, 255, 0) 100%);
  -webkit-mask-image: radial-gradient(ellipse 50% 100% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.5) 50%, transparent 100%);
  mask-image: radial-gradient(ellipse 50% 100% at 50% 0%, #000 0%, rgba(0, 0, 0, 0.5) 50%, transparent 100%);
  transition: opacity 900ms linear;
}
.column.is-on { opacity: 1; }

/* Morning mist lying on the lake. */
.mist {
  position: absolute;
  left: 0;
  right: 0;
  top: 498px;
  height: 110px;
  opacity: var(--mist);
  background:
    radial-gradient(ellipse 30% 60% at 18% 40%, rgba(255, 255, 255, 0.14), transparent 70%),
    radial-gradient(ellipse 34% 60% at 55% 55%, rgba(255, 255, 255, 0.12), transparent 70%),
    radial-gradient(ellipse 28% 60% at 86% 45%, rgba(255, 255, 255, 0.13), transparent 70%),
    linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.10) 35%, rgba(255, 255, 255, 0.05) 70%, rgba(255, 255, 255, 0) 100%);
}

/* Fireflies over the water at dusk and night: a handful of tiny lights that drift and blink. */
.fireflies { position: absolute; top: 0; right: 0; bottom: 0; left: 0; opacity: var(--fireflies); }
.fireflies i {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #fff1b0;
  box-shadow: 0 0 8px 3px rgba(255, 228, 140, 0.55);
  opacity: 0;
  will-change: transform, opacity;
}
.has-fireflies .fireflies i { animation: firefly var(--t, 8s) ease-in-out infinite alternate; }

.pines {
  position: absolute;
  left: 0;
  top: 404px;
  width: 1920px;
  height: 120px;
  fill: var(--pines);
}

/* A gentle darkening toward the edges, the way a lens sees it. */
.vignette {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: radial-gradient(ellipse 72% 70% at 50% 46%, rgba(0, 0, 0, 0) 55%, rgba(0, 0, 0, 0.38) 100%);
}

/* The pool of light under the selected app, in that app's colour. Two layers crossfade. */
.glow {
  position: absolute;
  left: 0;
  top: 0;
  width: 1100px;
  height: 520px;
  margin: -260px 0 0 -550px;
  background: radial-gradient(closest-side, var(--c, #fff) 0%, var(--c0, rgba(255, 255, 255, 0)) 100%);
  opacity: 0;
  transform: translate3d(960px, 600px, 0);
  transition: transform 420ms var(--ease-out), opacity 300ms linear;
  will-change: transform, opacity;
  pointer-events: none;
}
.glow.is-on { opacity: 0.3; }
.glow.is-dim { opacity: 0.18; }

/* ---- Content ---- */

.stage {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  opacity: 0;
  transition: opacity 320ms linear;
}
.is-ready .stage { opacity: 1; }

.masthead {
  position: absolute;
  left: var(--edge);
  right: var(--edge);
  top: 74px;
}

.greeting {
  font-size: 40px;
  font-weight: 500;
  color: var(--muted);
}

.clock {
  margin-top: 2px;
  font-family: 'Fraunces', serif;
  font-size: 236px;
  font-weight: 320;
  line-height: 0.9;
  letter-spacing: -0.035em;
  font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 0;
  font-feature-settings: 'lnum' 1, 'tnum' 1;
  text-shadow: 0 6px 40px rgba(0, 0, 0, 0.2);
}

.meridiem {
  margin-left: 22px;
  font-family: 'Atkinson', sans-serif;
  font-size: 44px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
  text-shadow: none;
}

.date {
  position: absolute;
  right: 0;
  top: 2px;
  font-size: 40px;
  font-weight: 500;
  color: var(--muted);
}

/* What the sky is doing: moon phase and the next sunrise or sunset. */
.detail {
  position: absolute;
  right: 0;
  top: 58px;
  font-size: 26px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--faint);
}

/* ---- Rows of apps ---- */

.row {
  position: absolute;
  left: var(--edge);
  display: flex;
  transition: transform 340ms var(--ease-out);
}
.row--big { top: 510px; }
.row--small { top: 878px; }

/* The big tiles are mirrored faintly in the lake below them (not in lean mode: the reflection
   is re-rendered every frame the row moves, which the TV can't afford). */
.screen:not(.lean) .row--big {
  -webkit-box-reflect: below 12px linear-gradient(rgba(0, 0, 0, 0) 58%, rgba(0, 0, 0, 0.26) 100%);
}

.tile {
  position: relative;
  flex: 0 0 auto;
  overflow: hidden;
  border-radius: 22px;
  background: linear-gradient(150deg, var(--tile-a) 0%, var(--tile-b) 55%, var(--tile-c) 100%);
  color: var(--ink, #fff);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1), 0 14px 30px rgba(0, 0, 0, 0.36);
  outline: 5px solid transparent;
  transform: scale(1);
  /* Only cheap properties animate: shadows are swapped instantly, which a TV GPU handles better. */
  transition: transform 280ms var(--ease-out), outline-color 160ms linear, opacity 200ms linear;
}
/* Square tiles, so the apps' own square logos fill them edge to edge. */
.row--big .tile { width: 208px; height: 208px; margin-right: 28px; border-radius: 42px; }
.row--small .tile { width: 146px; height: 146px; margin-right: 22px; border-radius: 30px; }
.tile:last-child { margin-right: 0; }

.tile-img {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A soft top light and a hairline edge over every logo, so they sit together as one set. */
.tile::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0) 42%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
  pointer-events: none;
}

/* Apps without a logo: their initial, set large, with the name underneath. */
.tile-initial {
  position: absolute;
  left: 0;
  right: 0;
  top: 22px;
  font-family: 'Fraunces', serif;
  font-size: 104px;
  font-weight: 500;
  line-height: 1;
  font-variation-settings: 'opsz' 144, 'SOFT' 100, 'WONK' 0;
  text-align: center;
}
.row--small .tile-initial { top: 14px; font-size: 72px; }

.tile-name {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 18px;
  font-size: 24px;
  font-weight: 700;
  line-height: 1.1;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.row--small .tile-name { bottom: 12px; font-size: 18px; }

/* A sweep of light across a tile when it is selected. */
.tile::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 32%, rgba(255, 255, 255, 0.28) 49%, rgba(255, 255, 255, 0) 66%);
  transform: translateX(-140%);
  pointer-events: none;
}
.tile.is-focused::after { animation: shine 820ms var(--ease-out) 80ms 1 backwards; }

.tile.is-focused {
  --fs: 1.1;
  z-index: 2;
  transform: scale(1.1);
  outline-color: var(--paper);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14), 0 26px 64px var(--shadow, rgba(0, 0, 0, 0.5));
  /* A slow breath once it has settled, so the selection feels alive. */
  animation: breathe-tile 3.4s ease-in-out 300ms infinite alternate;
}
.row--small .tile.is-focused { --fs: 1.12; transform: scale(1.12); }

.tile.is-moving {
  z-index: 3;
  transform: scale(1.1) translateY(-16px);
  outline-color: var(--paper);
  box-shadow: 0 44px 80px rgba(0, 0, 0, 0.6);
}
.row.is-arranging .tile:not(.is-moving) { opacity: 0.45; }

/* ---- Caption: names the selected app, like the label beside a painting ---- */

.caption {
  position: absolute;
  left: var(--edge);
  right: var(--edge);
  top: 756px;
  height: 80px;
  white-space: nowrap;
}

.caption-title.is-fresh { animation: caption-in 240ms var(--ease-out); }
.clock.is-tick { animation: tick-in 480ms var(--ease-out); }

.caption-title {
  display: inline-block;
  font-family: 'Fraunces', serif;
  font-size: 58px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.01em;
  font-variation-settings: 'opsz' 96, 'SOFT' 100, 'WONK' 0;
}

.caption-note {
  display: inline-block;
  margin-left: 28px;
  font-size: 30px;
  color: var(--muted);
}
.caption-note.is-error { color: var(--paper); }

.hint {
  position: absolute;
  right: 0;
  bottom: 18px;
  font-size: 27px;
  color: var(--faint);
  transition: opacity 200ms linear;
}
.hint.is-hidden { opacity: 0; }

/* ---- The hold-OK menu: move or hide an app ---- */

.menu {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 6;
  width: 380px;
  margin-left: -190px;
  padding: 12px;
  border-radius: 26px;
  background: var(--paper);
  color: var(--floor);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 140ms linear;
}
.menu.is-open { opacity: 1; }

.menu-title {
  padding: 8px 16px 12px;
  font-family: 'Fraunces', serif;
  font-size: 30px;
  font-weight: 500;
  font-variation-settings: 'opsz' 48, 'SOFT' 100, 'WONK' 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.menu-item {
  height: 62px;
  padding: 0 18px;
  border-radius: 16px;
  font-size: 30px;
  font-weight: 650;
  line-height: 62px;
}
.menu-item.is-focused { background: var(--floor); color: var(--paper); }

/* Fades the screen to the app's colour while it opens, so the press feels instant. */
.curtain {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 10;
  background: var(--c, #000);
  opacity: 0;
  transition: opacity 180ms linear;
  pointer-events: none;
}
.curtain.is-on { opacity: 1; }

/* Diagnostics, for sending a photo when something misbehaves. */
.diary {
  position: absolute;
  left: var(--edge);
  right: var(--edge);
  top: 90px;
  z-index: 20;
  max-height: 900px;
  overflow: hidden;
  padding: 26px 30px;
  border-radius: 22px;
  background: rgba(3, 4, 11, 0.9);
  color: #d6e4ff;
  font: 21px/1.45 monospace;
  white-space: pre-wrap;
}
.diary[hidden] { display: none; }

/* ---- The one entrance: the room fills in when the home screen first appears ---- */

.is-entering .masthead { animation: fade-in 520ms linear backwards; }
.is-entering .tile { animation: rise 600ms var(--ease-out) backwards; animation-delay: calc(160ms + var(--i, 0) * 34ms); }
.is-entering .caption { animation: fade-in 420ms linear 380ms backwards; }

@keyframes fade-in { from { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(28px) scale(0.98); } }
@keyframes shine { from { transform: translateX(-140%); } to { transform: translateX(140%); } }
@keyframes twinkle { from { opacity: 0.25; } to { opacity: 1; } }
@keyframes cloud-drift { from { transform: translate3d(-1.6%, 0, 0); } to { transform: translate3d(1.6%, 0, 0); } }
@keyframes turn { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes breathe { from { transform: scale(0.96); opacity: 0.85; } to { transform: scale(1.05); opacity: 1; } }
@keyframes sway { from { transform: translate3d(-7px, 0, 0); } to { transform: translate3d(7px, 0, 0); } }
@keyframes ripple {
  0% { opacity: 0; transform: scale(0.15); }
  12% { opacity: 0.55; }
  100% { opacity: 0; transform: scale(1); }
}
@keyframes breathe-tile { from { transform: scale(var(--fs, 1.1)); } to { transform: scale(calc(var(--fs, 1.1) + 0.022)); } }
@keyframes caption-in { from { opacity: 0; transform: translate3d(0, 10px, 0); } }
@keyframes tick-in { from { opacity: 0.35; transform: translate3d(0, 8px, 0); } }
@keyframes aurora-drift {
  from { transform: translate3d(-4%, 0, 0) skewX(-6deg); }
  to { transform: translate3d(4%, -2%, 0) skewX(6deg); }
}
@keyframes firefly {
  0% { opacity: 0; transform: translate3d(0, 0, 0); }
  30% { opacity: 0.9; }
  55% { opacity: 0.15; }
  80% { opacity: 0.8; }
  100% { opacity: 0; transform: translate3d(var(--dx, 30px), var(--dy, -16px), 0); }
}
@keyframes shimmer { from { opacity: 0.1; } to { opacity: 1; } }
@keyframes fly {
  0% { opacity: 0; transform: translate3d(var(--fly-x0), var(--fly-y0), 0) scale(var(--fly-s, 1)); }
  6% { opacity: 1; }
  94% { opacity: 1; }
  100% { opacity: 0; transform: translate3d(var(--fly-x1), var(--fly-y1), 0) scale(var(--fly-s, 1)); }
}
@keyframes fall {
  0% { opacity: 0; transform: translate3d(var(--m-x), var(--m-y), 0) rotate(var(--m-r)) translateX(0); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translate3d(var(--m-x), var(--m-y), 0) rotate(var(--m-r)) translateX(520px); }
}

/* ---- Lean mode: the same scene, rendered cheaply enough for the TV's graphics chip ----
   The TV runs out of fill-rate when many large translucent layers are composited every frame.
   In lean mode nothing in the scenery animates or transitions, so it is painted once a minute
   into one flat image; only small things keep moving, and the interface transitions are shorter. */
.lean .godrays, .lean .aurora--two, .lean .grain, .lean .glare-ring, .lean .glare-rays--fine { display: none; }
.lean .clouds, .lean .aurora, .lean .glare-rays, .lean .glare-halo, .lean .moon-glow,
.lean .glitter-layer:not(.glitter-layer--alt), .lean .tile.is-focused { animation: none !important; }
.lean .glare, .lean .moon, .lean .haze, .lean .glitter, .lean .column, .lean .godrays { transition: none !important; }
.lean .clouds, .lean .aurora, .lean .glare-rays, .lean .glare-halo, .lean .moon-glow, .lean .fireflies i { will-change: auto; }
.lean .twinkles i:nth-child(n+6), .lean .fireflies i:nth-child(n+6) { display: none; }
.lean .clock { text-shadow: none; }
.lean .glow { width: 760px; height: 380px; margin: -190px 0 0 -380px; transition: transform 300ms var(--ease-out), opacity 240ms linear; }
.lean .tile { transition: transform 200ms var(--ease-out), outline-color 120ms linear, opacity 160ms linear; box-shadow: 0 10px 22px rgba(0, 0, 0, 0.35); }
.lean .tile.is-focused { box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5); }
.lean .row { transition: transform 260ms var(--ease-out); }
.lean .tile::after { display: none; }
.lean .vignette { background: radial-gradient(ellipse 72% 70% at 50% 46%, rgba(0, 0, 0, 0) 60%, rgba(0, 0, 0, 0.3) 100%); }

@media (prefers-reduced-motion: reduce) {
  *, *::after { animation: none !important; transition: none !important; }
}
