/* Serene Studios — landing.
   Restraint is the point: the living light does the talking, the words
   nearly disappear. Every colour is a CSS variable set by palette.js
   from the visitor's local time; the values below are a calm morning
   fallback for first paint / no-JS. */
:root {
  --base: #ebe8e0;
  --surface: #f5f2ea;
  --ink: #2a2823;
  --ink-soft: #6b6a62;
  --accent: #3a6ea5;
  --glow: #f1cc6f;
  --shadow-deep: #bbb6a8;
  --shadow-soft: #dbd5c5;
  --highlight-inner: #ffffff;
  --sky-top: #f5efe2;
  --sky-bottom: #e6dfc8;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  /* Silver-lavender for the orbiting moon glow (.glow-orb.moon). */
  --moon: #9ea3c7;
  /* Guaranteed-readable ink (set per-phase by palette.js); these are the
     calm-morning fallbacks. */
  --contrast-ink: #2a2823;
  --contrast-ink-soft: #5f5d56;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink);
  background: linear-gradient(180deg, var(--sky-top) 0%, var(--sky-bottom) 100%);
  background-attachment: fixed;
  transition: color 1.2s var(--ease);
  line-height: 1.6;
  overflow-x: hidden;
}

/* The light source. A warm sun glow and a cool moon glow ride opposite
   ends of one orbit that turns once per day: sun high at midday, low at
   midnight, moon always 180° across. Each is a wide, heavily-blurred
   radial wash at low opacity, so the light reads like sun through
   frosted glass / heavy fog rather than a hard disc. */
.sky {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.orbit {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  transition: transform 4s var(--ease);
}
.orbit-sun  { transform: rotate(var(--orbit-angle, 0deg)); }
.orbit-moon { transform: rotate(calc(var(--orbit-angle, 0deg) + 180deg)); }
/* The glow sits one orbit-radius "up" along the wrapper's local axis;
   rotating the wrapper carries it 360° around the page centre. */
.glow-orb {
  position: absolute;
  width: 66vmax;
  height: 66vmax;
  left: -33vmax;
  top: calc(-33vmax - 40vmax);
  border-radius: 50%;
  filter: blur(min(9vmax, 110px));
  pointer-events: none;
  transition: background 4s var(--ease), opacity 4s var(--ease);
}
/* Each orb glows its own celestial's colour: the sun in the fixed warm
   amber of the icon's sun glyph, the moon in --moon, the same silver-
   lavender that lights the icon's moon. */
.glow-orb.sun  { background: radial-gradient(circle, #f5a84d 0%, transparent 66%); opacity: 0.40; }
.glow-orb.moon { background: radial-gradient(circle, var(--moon) 0%, color-mix(in srgb, var(--moon) 35%, transparent) 45%, transparent 70%); opacity: 0.42; transition: background 4s var(--ease), opacity 4s var(--ease); }

header, main, footer { position: relative; z-index: 1; }

.readout, .creed {
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--contrast-ink-soft);
  font-weight: 500;
}

.bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.5rem clamp(1.25rem, 5vw, 3rem);
  gap: 1rem;
  /* Liquid-glass scroll edge: a sticky frosted band that content slips
     under, tinted with the sky so it never collides with what's above.
     (View+LiquidGlass.swift uses a base-tint fade; here a backdrop blur +
     the same tint, masked to fade out below the bar.) */
  position: sticky;
  top: 0;
  z-index: 20;
}
.bar::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0; bottom: -22px;
  z-index: -1;
  pointer-events: none;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  background: linear-gradient(180deg, color-mix(in srgb, var(--sky-top) 72%, transparent) 0%, transparent 100%);
  -webkit-mask: linear-gradient(180deg, #000 52%, transparent 100%);
          mask: linear-gradient(180deg, #000 52%, transparent 100%);
}
.wordmark {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--contrast-ink);
}

/* The whole point: the product, floating in the light, surrounded by
   space. No explanation. */
.hero {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 1.1rem;
  padding: clamp(3rem, 12vh, 8rem) 1.5rem;
}
.hero h1 {
  font-size: clamp(2.8rem, 12vw, 5rem);
  font-weight: 200;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.tagline {
  font-size: clamp(1rem, 3.4vw, 1.35rem);
  font-weight: 300;
  /* contrast-ink-soft (vs raw --ink-soft) so it stays readable at the
     transition palettes — dusk, twilight, pre-dawn — where the raw
     ink-soft can land too close to base luminance. */
  color: var(--contrast-ink-soft);
  max-width: 24em;
  transition: color 1.2s var(--ease);
}
/* The "what is this" body copy. Sits right under the poetic tagline,
   in a quieter weight + tighter ink so the tagline still carries the
   headline read; this paragraph answers the cold visitor's first
   question without breaking the calm voice. */
.about {
  font-size: clamp(0.92rem, 2.6vw, 1.02rem);
  font-weight: 300;
  color: var(--contrast-ink-soft);
  max-width: 30em;
  line-height: 1.65;
  margin-top: -0.2rem;
  transition: color 1.2s var(--ease);
}
/* Slider hint — tracked-uppercase caption telling the visitor the
   atmosphere bar is interactive. Fades on first interaction via
   .is-faded (palette.js wires that). */
.slider-hint {
  margin-top: 0.7rem;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--contrast-ink-soft);
  font-weight: 500;
  opacity: 0.7;
  transition: opacity 0.5s var(--ease);
}
.slider-hint.is-faded { opacity: 0; pointer-events: none; }

/* Craft teaser — a quiet text link below the slider that gives a
   second discovery path to /craft (beyond the footer link). Subtle
   so it doesn't compete with the App Store CTA above it. */
.craft-teaser {
  margin-top: 2.4rem;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--contrast-ink-soft);
  text-decoration: none;
  font-weight: 400;
  transition: color 0.3s var(--ease), letter-spacing 0.3s var(--ease);
}
.craft-teaser:hover {
  color: var(--contrast-ink);
  letter-spacing: 0.06em;
}
.cta {
  margin-top: 1.4rem;
  padding: 0.85rem 2.2rem;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  font-weight: 500;
  font-size: 0.92rem;
  letter-spacing: 0.02em;
  box-shadow: 0 12px 30px -14px var(--shadow-deep), inset 0 1px 0 rgba(255,255,255,0.18);
  transition: background 4s var(--ease), transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.cta:hover { transform: translateY(-1px); box-shadow: 0 16px 36px -14px var(--shadow-deep), inset 0 1px 0 rgba(255,255,255,0.18); }

/* --- Momentos dial icon -------------------------------------------
   A 1:1 reproduction of the app icon: a palette.base squircle holding
   the dial — a raised, polished metal BEZEL ring (glow-tinted, lit from
   the top-left like the real icon), an orbiting specular glint, a dark
   recessed well with a glow wash, a 12-tick chapter ring, and the
   celestial scene: warm sun top-left, glow dot at centre, silver-
   lavender moon bottom-right. Tap it to fly the light through 24 hours.
   Every colour is palette-driven. */
.icon {
  --size: clamp(132px, 32vw, 196px);
  position: relative;
  width: var(--size);
  height: var(--size);
  margin-bottom: 0.4rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transition: transform 0.2s var(--ease);
}
.icon:active { transform: scale(0.98); }

/* The canvas paints the palette.base squircle itself (transparent
   corners), so a drop-shadow filter lifts that squircle off the sky the
   way a home-screen grid would. */
.dial {
  display: block;
  width: 100%;
  height: 100%;
  filter:
    drop-shadow(0 calc(var(--size) * 0.13) calc(var(--size) * 0.15) color-mix(in srgb, var(--shadow-deep) 70%, transparent))
    drop-shadow(0 calc(var(--size) * 0.03) calc(var(--size) * 0.05) color-mix(in srgb, var(--shadow-soft) 55%, transparent));
  transition: filter 4s var(--ease);
}

/* During a fly-by the palette changes every frame. Most elements on
   the page have transitions that depend on those CSS variables
   (device shadows, card backgrounds, atmosphere slider, day pill
   halo, neumorphic cards). Each variable change re-triggers an
   in-flight transition, and the browser interpolates between the
   old and new shadow blurs / colours each frame. Killing all
   transitions while .flyby is on body makes each frame paint
   instantly: the fly-by IS the animation, element-level transitions
   are noise during it. */
.flyby *,
.flyby *::before,
.flyby *::after { transition: none !important; }

/* --- Atmosphere slider --------------------------------------------
   Drag to scrub the light through the day. The track is the whole day's
   light as a glowing band (gradient set by palette.js from the palette
   at each hour); the thumb is the glow of the current hour. */
.atmosphere {
  -webkit-appearance: none;
  appearance: none;
  width: min(300px, 76vw);
  height: 9px;
  margin-top: 2.4rem;
  border-radius: 999px;
  /* JS replaces this with the full-day gradient; this is the no-JS fallback. */
  background: color-mix(in srgb, var(--glow) 40%, transparent);
  box-shadow:
    0 0 16px 0 color-mix(in srgb, var(--glow) 45%, transparent),
    0 0 6px 0 color-mix(in srgb, var(--glow) 60%, transparent),
    inset 0 0 0 1px color-mix(in srgb, var(--ink) 10%, transparent);
  cursor: pointer;
  outline: none;
  transition: box-shadow 1.2s var(--ease);
}
.atmosphere::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 21px; height: 21px;
  border-radius: 50%;
  background: var(--glow);
  border: 2.5px solid var(--surface);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--glow) 28%, transparent), 0 0 14px 2px color-mix(in srgb, var(--glow) 55%, transparent), 0 2px 6px -2px var(--shadow-deep);
  cursor: grab;
}
.atmosphere:active::-webkit-slider-thumb { cursor: grabbing; }
.atmosphere::-moz-range-thumb {
  width: 21px; height: 21px;
  border-radius: 50%;
  background: var(--glow);
  border: 2.5px solid var(--surface);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--glow) 28%, transparent), 0 0 14px 2px color-mix(in srgb, var(--glow) 55%, transparent);
  cursor: grab;
}

.foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  width: 100%;
  padding: 1.6rem clamp(1.25rem, 5vw, 3rem) 2rem;
}
.foot nav { display: flex; gap: 1.4rem; }
.foot a { color: var(--contrast-ink-soft); text-decoration: none; font-size: 0.85rem; letter-spacing: 0.02em; }
.foot a:hover { color: var(--contrast-ink); }

/* --- Craft showcase -----------------------------------------------
   The signature elements, rebuilt on canvas (craft.js) and floating in
   the same light. Pure experience: tiny labels, no explanation. */
.craft {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(2.75rem, 7vh, 4.5rem);
  padding: clamp(2.5rem, 8vh, 5rem) 1.5rem 3.5rem;
}
.craft-intro {
  font-size: clamp(0.95rem, 3vw, 1.2rem);
  font-weight: 300;
  color: var(--contrast-ink-soft);
  text-align: center;
  max-width: 22em;
}
.craft-stage {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(1.5rem, 5vw, 3.5rem);
  width: 100%;
}
.craft-piece {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Room below the dial for the deep drop-shadow to fall before the
     label, so it doesn't clip into the text. */
  gap: clamp(2.5rem, 6vw, 3.75rem);
}
.craft-canvas {
  display: block;
  width: clamp(176px, 38vw, 248px);
  height: clamp(176px, 38vw, 248px);
  /* Deep elevation so each dial sits proud of the page like a physical
     object — the canvas paints the disc with transparent margins, so the
     drop-shadow follows the disc. Tinted by the phase's deep shadow. */
  filter:
    drop-shadow(0 10px 15px color-mix(in srgb, var(--shadow-deep) 60%, transparent))
    drop-shadow(0 22px 32px color-mix(in srgb, var(--shadow-deep) 40%, transparent));
  transition: filter 1.2s var(--ease);
}
.craft-canvas-btn {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 50%;
  outline: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.2s var(--ease);
}
.craft-canvas-btn:focus { outline: none; }
.craft-canvas-btn:focus-visible { outline: 2px solid color-mix(in srgb, var(--accent) 70%, transparent); outline-offset: 4px; border-radius: 50%; }
.craft-canvas-btn:active { transform: scale(0.985); }
.craft-label {
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--contrast-ink-soft);
  font-weight: 500;
}

/* --- NeumorphicSurface spine (port of NeumorphicSurface.swift) ------
   Raised = floating card: directional punch + soft drops on the shadow
   side, a specular halo + inner highlight on the sun side. Pressed =
   engraved: two inset shadows following the sun. All offsets ride the
   --shadow-x/--shadow-y sun vector so the soft-UI light tracks the day. */
.neu-raised {
  background: var(--surface);
  border-radius: 20px;
  box-shadow:
    /* elevation: punch + soft drop on the shadow side */
    calc(var(--shadow-x) * 5px) calc(var(--shadow-y) * 5px) 9px color-mix(in srgb, var(--shadow-deep) 95%, transparent),
    calc(var(--shadow-x) * 13px) calc(var(--shadow-y) * 13px) 24px color-mix(in srgb, var(--shadow-deep) 62%, transparent),
    /* specular halo on the sun side — pops the card off the page */
    calc(var(--shadow-x) * -7px) calc(var(--shadow-y) * -7px) 18px color-mix(in srgb, var(--highlight-inner) 60%, transparent),
    /* inner highlight bevel on the sun edge */
    inset calc(var(--shadow-x) * -9px) calc(var(--shadow-y) * -9px) 16px color-mix(in srgb, var(--highlight-inner) 90%, transparent),
    /* the bright glow rim — the day's light catching the raised edge.
       This is the cue that reads even in dark mode (the app's rim glint). */
    inset calc(var(--shadow-x) * -2px) calc(var(--shadow-y) * -2px) 2px color-mix(in srgb, var(--glow) 55%, transparent),
    /* inner shadow on the far (shadow) edge */
    inset calc(var(--shadow-x) * 7px) calc(var(--shadow-y) * 7px) 13px color-mix(in srgb, var(--shadow-deep) 45%, transparent);
  /* Snap with the palette (like the dials + page), not a slow ease — a long
     transition made the cards visibly lag behind everything else. The short
     duration just smooths the tap raise->press flip. */
  transition: box-shadow 0.18s var(--ease), background 0.18s var(--ease);
}
.neu-pressed {
  background: color-mix(in srgb, var(--shadow-deep) 12%, var(--surface));
  border-radius: 20px;
  box-shadow:
    inset calc(var(--shadow-x) * 6px) calc(var(--shadow-y) * 6px) 11px color-mix(in srgb, var(--shadow-deep) 95%, transparent),
    inset calc(var(--shadow-x) * -5px) calc(var(--shadow-y) * -5px) 10px color-mix(in srgb, var(--highlight-inner) 85%, transparent),
    inset calc(var(--shadow-x) * -1.5px) calc(var(--shadow-y) * -1.5px) 1.5px color-mix(in srgb, var(--glow) 30%, transparent);
  transition: box-shadow 0.18s var(--ease), background 0.18s var(--ease);
}

/* --- Activity cards + task rows ------------------------------------ */
.craft-cards {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: min(440px, 92vw);
}
.act-card, .task-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  min-height: 64px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  outline: none;
}
.act-card:focus-visible, .task-row:focus-visible { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent); }
.act-icon {
  flex: none;
  width: 26px; height: 26px;
  color: var(--accent);
  display: grid;
  place-items: center;
}
.act-icon svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.act-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.act-title { font-size: 0.98rem; color: var(--contrast-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: color 0.2s var(--ease); }
.act-sub { font-size: 0.72rem; color: var(--contrast-ink-soft); font-variant-numeric: tabular-nums; }
.act-status { flex: none; display: flex; align-items: center; }
.is-done .act-title { color: var(--contrast-ink-soft); }

/* Checklist ring: hollow dim circle -> glowing ring + check on complete.
   Two-step beat — the ring lights first, the check lands 0.12s later;
   undo clears both at once (no delay). */
.check-ring {
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--shadow-deep) 35%, transparent);
  display: grid; place-items: center;
  transition: border-color 0.14s var(--ease), border-width 0.14s var(--ease), box-shadow 0.14s var(--ease);
}
.is-done .check-ring {
  border: 3px solid var(--glow);
  box-shadow: 0 0 5px color-mix(in srgb, var(--glow) 60%, transparent);
}
.check-ring svg { width: 13px; height: 13px; fill: none; stroke: var(--glow); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; opacity: 0; transition: opacity 0.12s var(--ease); }
.is-done .check-ring svg { opacity: 1; transition-delay: 0.12s; }

/* Segmented LED bar */
.segbar { display: flex; gap: 3px; width: 84px; }
.seg {
  flex: 1; height: 6px; border-radius: 2px;
  background: color-mix(in srgb, var(--shadow-deep) 45%, transparent);
  box-shadow: inset 1px 1px 2px color-mix(in srgb, var(--shadow-deep) 35%, transparent);
  transition: background 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.seg.lit { background: var(--glow); box-shadow: 0 0 4px color-mix(in srgb, var(--glow) 50%, transparent); }

/* LED dot */
.led-dot {
  width: 13px; height: 13px; border-radius: 50%; flex: none;
  background: color-mix(in srgb, var(--shadow-deep) 60%, transparent);
  box-shadow: inset 1px 1px 2px color-mix(in srgb, var(--shadow-deep) 40%, transparent);
  transition: background 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.led-dot.on {
  background: var(--glow);
  box-shadow: 0 0 8px color-mix(in srgb, var(--glow) 85%, transparent), 0 0 16px color-mix(in srgb, var(--glow) 45%, transparent);
}

/* Tally canvas (hand-drawn marks, painted by craft.js) */
.tally-canvas { display: block; width: 156px; height: 40px; }

/* Task row checkbox: hollow circle -> filled glow circle + check */
.task-check {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  border: 2px solid var(--ink-soft);
  display: grid; place-items: center;
  transition: border-color 0.14s var(--ease), background 0.14s var(--ease), box-shadow 0.14s var(--ease);
}
.task-check svg { width: 13px; height: 13px; fill: none; stroke: var(--surface); stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; opacity: 0; transition: opacity 0.12s var(--ease); }
.task-row.is-done .task-check {
  border-color: var(--glow); background: var(--glow);
  box-shadow: 0 0 6px color-mix(in srgb, var(--glow) 55%, transparent);
}
.task-row.is-done .task-check svg { opacity: 1; transition-delay: 0.12s; }
.task-title { font-size: 0.98rem; color: var(--contrast-ink); transition: color 0.2s var(--ease); }
.task-row.is-done .task-title { color: var(--contrast-ink-soft); text-decoration: line-through; text-decoration-color: var(--contrast-ink-soft); }
.sparkle { color: var(--glow); margin-left: 6px; filter: drop-shadow(0 0 2px color-mix(in srgb, var(--glow) 50%, transparent)); }

/* --- Extruded surface (molded rise) — NeumorphicSurface.raisedExtruded.
   The card is the SAME material as the background (palette.base) and the
   surrounding material ramps up to meet it: a warm glow halo + a white
   specular peak on the sun side, a soft cast on the shadow side. No fill
   seam, no rim — only the blurred bleed reads. */
.neu-extruded {
  position: relative;
  background: var(--base);
  border-radius: 20px;
  /* Deep drop on the shadow side + a lit/shadowed bevel on the plateau's
     own edges, so the top surface reads as a raised plane (the blurred
     ::before / ::after below are the molded ramp around it). */
  box-shadow:
    calc(var(--shadow-x) * 11px) calc(var(--shadow-y) * 11px) 22px color-mix(in srgb, var(--shadow-deep) 72%, transparent),
    /* inset shadows render opposite their offset, so offset toward shadow
       puts the lit bevel on the SUN edge, and vice-versa. */
    inset calc(var(--shadow-x) * 2px) calc(var(--shadow-y) * 2px) 4px color-mix(in srgb, var(--glow) 48%, transparent),
    inset calc(var(--shadow-x) * -2px) calc(var(--shadow-y) * -2px) 5px color-mix(in srgb, var(--shadow-deep) 55%, transparent);
  transition: box-shadow 0.18s var(--ease), background 0.18s var(--ease);
}
/* The molded rise: a blurred linear gradient running along the sun vector
   — glow at the sun corner, transparent through the middle, shadowDeep at
   the shadow corner. The base-filled tile covers the centre, so only the
   blurred bleed past the edges shows: bright on the sun side, dark on the
   shadow side. (NeumorphicSurface.raisedExtruded's moldedRiseGlow.) */
.neu-extruded::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 20px;
  z-index: -1;
  background: linear-gradient(var(--rise-angle, 135deg),
    color-mix(in srgb, var(--glow) 100%, transparent) 0%,
    color-mix(in srgb, var(--glow) 35%, transparent) 26%,
    transparent 48%,
    color-mix(in srgb, var(--shadow-deep) 70%, transparent) 74%,
    color-mix(in srgb, var(--shadow-deep) 100%, transparent) 100%);
  filter: blur(12px);
}
/* The specular peak — a tighter, brighter white highlight on the sun side
   (NeumorphicSurface.moldedRisePeak). This is the visible "shine" the warm
   glow alone doesn't give in dark mode. */
.neu-extruded::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 20px;
  z-index: -1;
  background: linear-gradient(var(--rise-angle, 135deg),
    color-mix(in srgb, #ffffff 95%, transparent) 0%,
    color-mix(in srgb, #ffffff 35%, transparent) 22%,
    transparent 42%,
    transparent 100%);
  filter: blur(7px);
}

/* --- Widget trio (Phase 3) ----------------------------------------
   Faithful canvas + CSS ports of the iOS widget surfaces:
   lock-screen circular, small home-screen, medium home-screen. The
   dial is canvas (mirrors TodayProgressWidget.ProgressArc.swift); the
   widget card chrome + activity rows are CSS, riding the palette's
   sun vector for directional shadow + warm glow halo (WidgetSurface
   .swift's .floating treatment, ported with the same magnitudes). */
.craft-widgets {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(1.75rem, 5vw, 3rem);
  width: 100%;
}
.widget-piece {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.3rem;
}
.widget-medium-piece { flex-basis: 100%; }
@media (min-width: 760px) {
  .widget-medium-piece { flex-basis: auto; }
}

/* The shared widget card. palette.surface fill + directional drop
   shadow + warm rim glow on the sun side. Mirrors WidgetSurface
   .floating (no halo bloom — the drop shadow alone carries the lift,
   exactly like the in-widget treatment). */
.widget-card {
  position: relative;
  background: var(--surface);
  border-radius: 22px;
  box-shadow:
    /* close directional punch */
    calc(var(--shadow-x) * 5px) calc(var(--shadow-y) * 5px) 9px color-mix(in srgb, var(--shadow-deep) 60%, transparent),
    /* soft drop further out */
    calc(var(--shadow-x) * 12px) calc(var(--shadow-y) * 12px) 22px color-mix(in srgb, var(--shadow-deep) 45%, transparent),
    /* warm rim catch on the sun edge — same vocabulary as the
       in-app neumorphic rim glint */
    inset calc(var(--shadow-x) * -1.5px) calc(var(--shadow-y) * -1.5px) 1.5px color-mix(in srgb, var(--glow) 45%, transparent);
  transition: background 0.18s var(--ease), box-shadow 0.18s var(--ease);
  border: 0;
  cursor: pointer;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}
.widget-card:focus { outline: none; }
.widget-card:focus-visible {
  box-shadow:
    calc(var(--shadow-x) * 5px) calc(var(--shadow-y) * 5px) 9px color-mix(in srgb, var(--shadow-deep) 60%, transparent),
    calc(var(--shadow-x) * 12px) calc(var(--shadow-y) * 12px) 22px color-mix(in srgb, var(--shadow-deep) 45%, transparent),
    inset 0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent);
}

/* Small home-screen widget — square cell. Percent + streak overlays
   sit at the dial's top corners; phase label at the bottom. */
.widget-small {
  width: 172px; height: 190px;
  padding: 12px 12px 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.widget-small .widget-dial-canvas {
  display: block;
  width: 100%;
  flex: 1;
  min-height: 0;
  /* Bezel's bottom shadow blur extends ~7% of dim past the disc edge;
     keep the phase label out of that bleed zone with a clear gap. */
  margin-bottom: 10px;
}
.widget-phase {
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  color: var(--contrast-ink-soft);
  text-transform: uppercase;
}
.widget-corner {
  position: absolute;
  font-size: 0.66rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--contrast-ink-soft);
  z-index: 1;
  pointer-events: none;
  letter-spacing: 0.01em;
}
.widget-corner-tl { top: 10px; left: 12px; }
.widget-corner-tr { top: 10px; right: 12px; }
.widget-streak {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  color: var(--glow);
}
.widget-streak svg { width: 12px; height: 12px; fill: currentColor; }
.widget-streak.is-hidden { display: none; }

/* Medium home-screen widget — wider rectangle. Dial column on the
   left, activity rows + footer on the right. */
.widget-medium {
  width: min(360px, 92vw);
  height: 190px;
  padding: 12px;
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 10px;
}
.widget-medium-left {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.widget-dial-btn {
  position: relative;
  width: 100%;
  height: 100%;
  background: none; border: 0; padding: 0;
  cursor: pointer; outline: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  -webkit-tap-highlight-color: transparent;
}
.widget-medium .widget-dial-canvas {
  display: block;
  width: 100%;
  flex: 1;
  min-height: 0;
  /* Same shadow-bleed buffer as the small widget. */
  margin-bottom: 10px;
}

.widget-medium-right {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.widget-rows {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  min-height: 0;
}
/* Inactive pager pages are hidden — both pages live in the DOM so
   per-row toggle state survives paging, but only the current one
   renders. !important because the large widget's .widget-rows-large
   selector lives later in the file with equal specificity and would
   otherwise win the cascade. */
.widget-rows.is-hidden { display: none !important; }
/* Nested widgetCard — the in-widget rows each use widgetCard with
   cornerRadius 10. Same sun-vector shadow + glow rim vocabulary. */
.widget-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border: 0;
  border-radius: 10px;
  background: color-mix(in srgb, var(--surface) 88%, var(--base));
  box-shadow:
    calc(var(--shadow-x) * 1.5px) calc(var(--shadow-y) * 1.5px) 3px color-mix(in srgb, var(--shadow-deep) 50%, transparent),
    inset calc(var(--shadow-x) * -1px) calc(var(--shadow-y) * -1px) 1px color-mix(in srgb, var(--glow) 35%, transparent);
  cursor: pointer;
  outline: none;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.widget-row.is-done {
  background: color-mix(in srgb, var(--glow) 8%, var(--surface));
}
.widget-row-icon {
  flex: none;
  width: 16px; height: 16px;
  color: var(--accent);
  display: grid; place-items: center;
}
.widget-row-icon svg {
  width: 100%; height: 100%;
  fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.widget-row.is-done .widget-row-icon { color: var(--glow); }
.widget-row-body {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  overflow: hidden;
}
.widget-row-title {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--contrast-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.widget-row-sub {
  font-size: 0.6rem;
  color: var(--contrast-ink-soft);
  font-variant-numeric: tabular-nums;
}
.widget-row-check {
  flex: none;
  width: 18px; height: 18px;
  color: var(--glow);
  display: grid; place-items: center;
}
.widget-row-check svg { width: 100%; height: 100%; }
.widget-row-check-empty {
  color: color-mix(in srgb, var(--contrast-ink-soft) 60%, transparent);
}
.widget-row-check-empty svg { fill: none; stroke: currentColor; stroke-width: 1.4; }
.widget-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 4px 0;
  gap: 6px;
  font-size: 0.56rem;
  letter-spacing: 0.05em;
  color: var(--contrast-ink);
  font-weight: 500;
}
.widget-foot-label {
  flex: none;
  font-variant-numeric: tabular-nums;
}
.widget-dots {
  flex: 1;
  display: inline-flex; gap: 4px; align-items: center;
  justify-content: flex-end;
}
.widget-dot {
  width: 3px; height: 3px; border-radius: 50%;
  background: color-mix(in srgb, var(--contrast-ink-soft) 50%, transparent);
}
.widget-dot.is-current {
  width: 4.5px; height: 4.5px;
  background: var(--contrast-ink);
}
.widget-pager-chevron {
  flex: none;
  background: none; border: 0;
  padding: 1px 2px;
  cursor: pointer; outline: none;
  -webkit-tap-highlight-color: transparent;
  color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center;
}
.widget-pager-chevron svg {
  width: 13px; height: 13px;
  fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.widget-pager-chevron:active { transform: scale(0.92); }

/* Large home-screen widget. Same vocabulary as medium; left column
   stacks dial -> month calendar -> phase label; right column fits up
   to 7 activity rows + the footer (section + dots + chevron). */
.widget-large {
  width: min(380px, 92vw);
  height: 380px;
  padding: 12px;
  display: grid;
  grid-template-columns: 152px 1fr;
  gap: 10px;
}
.widget-large-left {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
}
.widget-large-dial-btn {
  height: auto;
  flex: 0 0 auto;
}
.widget-large .widget-dial-canvas {
  display: block;
  width: 130px;
  height: 130px;
}
.widget-large-right {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.widget-large-right .widget-rows-large {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-height: 0;
}
/* Slightly tighter rows on the large so 7 of them stack cleanly. */
.widget-rows-large .widget-row {
  padding: 5px 8px;
}
.widget-rows-large .widget-row-title { font-size: 0.71rem; }
.widget-rows-large .widget-row-sub   { font-size: 0.58rem; }

/* Month calendar — the in-widget grid (TodayProgressWidget.monthGrid).
   7 columns of small cells, today ringed, past days carry a glow disc
   sized by completion tier, future days dim. JS populates the cells
   for the real current month. */
.widget-calendar {
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.widget-calendar-header {
  font-size: 0.55rem;
  letter-spacing: 0.18em;
  font-weight: 500;
  color: var(--contrast-ink);
  text-transform: uppercase;
}
.widget-calendar-weekdays,
.widget-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 14px);
  gap: 2px;
}
.widget-calendar-weekdays {
  font-size: 0.48rem;
  letter-spacing: 0.08em;
  color: var(--contrast-ink-soft);
  text-align: center;
}
.widget-calendar-weekdays span {
  width: 14px;
  text-transform: uppercase;
}
.widget-calendar-grid { row-gap: 3px; }
.widget-calendar-cell {
  width: 14px; height: 14px;
  position: relative;
  display: grid;
  place-items: center;
}
.widget-calendar-glyph {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--glow);
  opacity: 0;
}
.widget-calendar-cell.is-future .widget-calendar-glyph {
  width: 3px; height: 3px;
  opacity: 0.28;
}
.widget-calendar-cell.is-muted .widget-calendar-glyph {
  opacity: 0.42;
}
.widget-calendar-cell.is-baseline .widget-calendar-glyph {
  opacity: 0.85;
  box-shadow: 0 0 2px color-mix(in srgb, var(--glow) 50%, transparent);
}
.widget-calendar-cell.is-full .widget-calendar-glyph {
  width: 6px; height: 6px;
  opacity: 1;
  box-shadow: 0 0 3px color-mix(in srgb, var(--glow) 70%, transparent);
}
.widget-calendar-cell.is-excellence .widget-calendar-glyph {
  width: 7px; height: 7px;
  opacity: 1;
  box-shadow:
    0 0 4px color-mix(in srgb, var(--glow) 90%, transparent),
    0 0 8px color-mix(in srgb, var(--glow) 50%, transparent);
}
.widget-calendar-cell.is-today {
  /* Raised tile chrome — palette.surface fill with a directional
     drop shadow + a sun-aligned highlight, matching the in-widget
     TodayCellChrome's vocabulary. */
  background: var(--surface);
  border-radius: 3px;
  box-shadow:
    calc(var(--shadow-x) * 0.6px) calc(var(--shadow-y) * 0.6px) 1.5px color-mix(in srgb, var(--shadow-deep) 60%, transparent),
    inset calc(var(--shadow-x) * -0.6px) calc(var(--shadow-y) * -0.6px) 0.8px color-mix(in srgb, var(--glow) 55%, transparent);
}
.widget-large .widget-phase {
  margin-top: 8px;
}

/* Lock-screen widget. On a real iOS lock screen there is NO card
   chrome — the accessory just floats over the wallpaper with iOS's
   vibrancy treatment (content tints dark or light to read against
   the wallpaper underneath). We approximate that here: no backdrop,
   the ring + flame/check render directly on the page using the
   palette's --contrast-ink so they always read against whatever
   palette is active, with opacity for the "vibrancy" feel. */
.widget-lock-piece { gap: 1.3rem; }
.widget-lock-bg {
  /* Transparent — no card, no chrome. Just a sizing wrapper so the
     ring lives at a consistent footprint next to the other widgets. */
  width: 120px; height: 120px;
  display: grid;
  place-items: center;
}
.widget-lock {
  position: relative;     /* sit above the ::before backdrop */
  z-index: 1;
  width: 76px; height: 76px;
  background: none; border: 0; padding: 0;
  cursor: pointer; outline: none;
  -webkit-tap-highlight-color: transparent;
  border-radius: 50%;
}
.lock-canvas { display: block; width: 100%; height: 100%; }

/* The day-pill + streak-pill row that follows the widget trio. */
.craft-pill {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(2rem, 6vw, 4rem);
}
.pill-demo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}

/* Streak pill — the flame.fill + count chip the in-app uses on
   Today's header and in every widget corner. Same capsule chrome
   vocabulary as the day-pill (glow rim + warm halo) but tighter,
   the flame leading rather than a check, count in rounded mono. */
.streak-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 14px; border: 0; cursor: pointer; outline: none;
  border-radius: 999px;
  background: var(--surface);
  box-shadow:
    inset 0 0 0 0.6px color-mix(in srgb, var(--glow) 45%, transparent),
    0 0 24px 2px color-mix(in srgb, var(--glow) 50%, transparent),
    0 0 48px 1px color-mix(in srgb, var(--glow) 25%, transparent);
  color: var(--glow);
  transition: box-shadow 0.5s var(--ease), background 0.18s var(--ease);
}
.streak-pill:focus { outline: none; }
.streak-pill:focus-visible {
  box-shadow:
    inset 0 0 0 0.6px color-mix(in srgb, var(--glow) 45%, transparent),
    0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent),
    0 0 24px 2px color-mix(in srgb, var(--glow) 50%, transparent);
}
.streak-flame {
  width: 14px; height: 14px;
  fill: currentColor;
  filter:
    drop-shadow(0 0 2px color-mix(in srgb, var(--glow) 70%, transparent))
    drop-shadow(0 0 5px color-mix(in srgb, var(--glow) 35%, transparent));
}
.streak-count {
  font-size: 0.92rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  font-family: ui-rounded, -apple-system, BlinkMacSystemFont, sans-serif;
}
/* Big milestone counts (3+ digits) — gently widen padding so the
   pill still reads as a chip rather than a stretched capsule. */
.streak-pill.is-big { padding: 6px 16px; }

/* Day-complete pill — capsule, glow text + icon, with the halo bloom.
   Excellence swaps the check for sparkles and brightens the halo (×1.6). */
.day-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 13px; border: 0; cursor: pointer; outline: none;
  border-radius: 999px;
  background: var(--surface);
  box-shadow:
    inset 0 0 0 0.6px color-mix(in srgb, var(--glow) 40%, transparent),
    0 0 30px 3px color-mix(in srgb, var(--glow) 55%, transparent),
    0 0 60px 2px color-mix(in srgb, var(--glow) 28%, transparent);
  color: var(--glow);
  transition: box-shadow 0.5s var(--ease), background 0.18s var(--ease);
}
.day-pill .pill-icon { width: 13px; height: 13px; fill: currentColor; }
.day-pill .pill-label { font-size: 0.7rem; letter-spacing: 0.2em; font-weight: 600; }
.day-pill.excellence {
  box-shadow:
    inset 0 0 0 0.6px color-mix(in srgb, var(--glow) 55%, transparent),
    0 0 44px 5px color-mix(in srgb, var(--glow) 70%, transparent),
    0 0 80px 4px color-mix(in srgb, var(--glow) 40%, transparent);
}

/* --- Calendar day glyphs ------------------------------------------
   The in-app calendar's full visual vocabulary as a row of showcase
   tiles. Mirrors CompletionGlyph + RoutineGlyph from CalendarScreen
   .swift, scaled up so the bloom tiers + rest-day moon + routine
   corner dots + Fitness rings + achievement sparkle all read clearly.
   Palette-driven: every halo + glow is tinted with --glow so the tiles
   carry the same warm light the rest of the page does. */
.craft-days {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(1rem, 3vw, 2rem);
  width: 100%;
  max-width: 880px;
  margin: 0 auto;
}
.day-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
}
.day-cell {
  position: relative;
  width: 60px; height: 60px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  transition: background 0.18s var(--ease);
}
.day-glyph {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--glow);
  display: block;
}

/* Baseline tier: dialled-down disc with a small bloom — matches
   CompletionGlyph's at-baseline state (fillOpacity ≈ score). */
.day-baseline .day-glyph {
  width: 14px; height: 14px;
  opacity: 0.85;
  box-shadow:
    0 0 6px color-mix(in srgb, var(--glow) 55%, transparent),
    0 0 12px color-mix(in srgb, var(--glow) 30%, transparent);
}

/* Steady (Full) tier: brighter disc + medium halo. */
.day-full .day-glyph {
  width: 18px; height: 18px;
  box-shadow:
    0 0 10px color-mix(in srgb, var(--glow) 75%, transparent),
    0 0 22px color-mix(in srgb, var(--glow) 40%, transparent);
}

/* Excellence: full corona — disc + multi-layer bloom + the sparkle
   that lives on every excellence-tier surface in the app (dial,
   day-complete pill, here). */
.day-excellence .day-glyph {
  width: 22px; height: 22px;
  box-shadow:
    0 0 12px color-mix(in srgb, var(--glow) 95%, transparent),
    0 0 28px color-mix(in srgb, var(--glow) 60%, transparent),
    0 0 48px color-mix(in srgb, var(--glow) 30%, transparent);
}
.day-sparkle-overlay {
  position: absolute;
  top: -2px; right: -2px;
  width: 18px; height: 18px;
  pointer-events: none;
}
.day-sparkle-overlay svg {
  width: 100%; height: 100%;
  fill: var(--glow);
  filter:
    drop-shadow(0 0 4px color-mix(in srgb, var(--glow) 90%, transparent))
    drop-shadow(0 0 10px color-mix(in srgb, var(--glow) 50%, transparent));
}

/* Rest day: crescent moon. Same glyph the in-app calendar uses for
   intentional rest days — soft glow so the day reads as deliberate,
   not absent. */
.day-rest svg {
  width: 28px; height: 28px;
  color: var(--glow);
  fill: currentColor;
  filter:
    drop-shadow(0 0 4px color-mix(in srgb, var(--glow) 60%, transparent))
    drop-shadow(0 0 10px color-mix(in srgb, var(--glow) 30%, transparent));
}

/* Sun + moon routines: corner accents on the day disc (RoutineGlyph's
   wrap). Warm sun in the upper-left for the morning routine, cool moon
   in the lower-right for the evening routine. */
.day-routines .day-glyph {
  width: 14px; height: 14px;
  opacity: 0.85;
  box-shadow: 0 0 6px color-mix(in srgb, var(--glow) 55%, transparent);
}
.day-sun-corner,
.day-moon-corner {
  position: absolute;
  width: 6px; height: 6px;
  border-radius: 50%;
}
.day-sun-corner {
  top: 12px; left: 12px;
  background: #f4a86a;
  box-shadow:
    0 0 4px color-mix(in srgb, #f4a86a 90%, transparent),
    0 0 8px color-mix(in srgb, #f4a86a 50%, transparent);
}
.day-moon-corner {
  bottom: 12px; right: 12px;
  background: #9ea3c7;
  box-shadow:
    0 0 4px color-mix(in srgb, #9ea3c7 75%, transparent),
    0 0 8px color-mix(in srgb, #9ea3c7 40%, transparent);
}

/* Fitness ring closure DOTS — the in-app vocabulary. Three small
   tinted dots on a ~60° diagonal arc (Move red / Exercise green /
   Stand cyan), centered in the cell. "All closed" adds the white
   sparkle with RGB halos echoing each ring's color. Mirrors
   CalendarRingDots.swift. */
.day-ringdots,
.day-allclosed {
  position: relative;
}
.ringdot {
  position: absolute;
  width: 8px; height: 8px;
  border-radius: 50%;
}
/* Cluster sits in the lower-left quadrant matching the in-app cell,
   so the achievement sparkle can tuck into the bottom-left corner
   just below the Stand dot. */
.day-ringdots .ringdot-move,
.day-allclosed .ringdot-move {
  top: 18px; left: 18px;
  background: #fa114f;
  box-shadow:
    0 0 4px color-mix(in srgb, #fa114f 90%, transparent),
    0 0 8px color-mix(in srgb, #fa114f 50%, transparent);
}
.day-ringdots .ringdot-exercise,
.day-allclosed .ringdot-exercise {
  top: 26px; left: 24px;
  background: #92e82a;
  box-shadow:
    0 0 4px color-mix(in srgb, #92e82a 90%, transparent),
    0 0 8px color-mix(in srgb, #92e82a 50%, transparent);
}
.day-ringdots .ringdot-stand,
.day-allclosed .ringdot-stand {
  top: 34px; left: 30px;
  background: #1cd4d9;
  box-shadow:
    0 0 4px color-mix(in srgb, #1cd4d9 90%, transparent),
    0 0 8px color-mix(in srgb, #1cd4d9 50%, transparent);
}

/* "All closed" achievement sparkle — white core with each ring's
   color echoed in the drop-shadow halo. Tucked into the bottom-left
   corner of the cell, matching the in-app cell where the sparkle
   sits below-left of the Stand dot. */
.allclosed-sparkle {
  position: absolute;
  bottom: 6px; left: 8px;
  width: 12px; height: 12px;
  pointer-events: none;
}
.allclosed-sparkle svg {
  width: 100%; height: 100%;
  fill: #ffffff;
  filter:
    drop-shadow(0 0 3px rgba(255,255,255,0.95))
    drop-shadow(0 0 6px color-mix(in srgb, #fa114f 50%, transparent))
    drop-shadow(0 0 8px color-mix(in srgb, #92e82a 35%, transparent))
    drop-shadow(0 0 10px color-mix(in srgb, #1cd4d9 30%, transparent));
}

/* --- The full-day feature ----------------------------------------
   One bigger tile showing all the vocabulary at once: rings closed,
   centre disc at excellence with corona, sun + moon corners, sparkle
   in the top-right. The "everything went right today" payoff. */
.craft-day-feature {
  display: flex;
  justify-content: center;
  width: 100%;
}
.day-feature-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
}
/* Full-day feature cell: a faithful port of the in-app "today + full
   day" calendar cell. Neumorphic raised chrome + every status glyph
   the calendar can carry, positioned as it is in the app. */
.day-feature-cell {
  position: relative;
  width: 168px; height: 168px;
  border-radius: 20px;
  background: var(--surface);
  box-shadow:
    calc(var(--shadow-x) * 5px) calc(var(--shadow-y) * 5px) 11px color-mix(in srgb, var(--shadow-deep) 60%, transparent),
    calc(var(--shadow-x) * 13px) calc(var(--shadow-y) * 13px) 26px color-mix(in srgb, var(--shadow-deep) 45%, transparent),
    inset calc(var(--shadow-x) * -1.5px) calc(var(--shadow-y) * -1.5px) 1.5px color-mix(in srgb, var(--glow) 55%, transparent);
}

/* Sun icon upper-left — sun.max.fill silhouette (filled disc + 8 rays). */
.feature-sun {
  position: absolute;
  top: 14px; left: 14px;
  width: 26px; height: 26px;
  color: #f4a86a;
}
.feature-sun circle { fill: currentColor; }
.feature-sun path   { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; }
.feature-sun {
  filter:
    drop-shadow(0 0 5px color-mix(in srgb, #f4a86a 95%, transparent))
    drop-shadow(0 0 12px color-mix(in srgb, #f4a86a 55%, transparent));
}

/* Excellence sparkle upper-right — glow-tinted, matches the dial's
   sparkle when progress > 1.0. */
.feature-sparkle-tr {
  position: absolute;
  top: 16px; right: 16px;
  width: 20px; height: 20px;
  fill: var(--glow);
  filter:
    drop-shadow(0 0 4px color-mix(in srgb, var(--glow) 95%, transparent))
    drop-shadow(0 0 10px color-mix(in srgb, var(--glow) 50%, transparent));
}

/* Centre excellence glyph + corona. The "headline" of the day:
   a warm glow disc with a triple-layer bloom. */
.feature-glyph {
  position: absolute;
  top: 50%; left: 54%;
  transform: translate(-50%, -50%);
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--glow);
  box-shadow:
    0 0 16px color-mix(in srgb, var(--glow) 100%, transparent),
    0 0 34px color-mix(in srgb, var(--glow) 70%, transparent),
    0 0 60px color-mix(in srgb, var(--glow) 35%, transparent);
}

/* Fitness ring CLOSURE DOTS (CalendarRingDots.swift). Three small
   dots on a ~60° arc in the lower-left quadrant, RGB-tinted to match
   Apple Fitness's Move (red) / Exercise (green) / Stand (cyan). */
.feature-ring-dot {
  position: absolute;
  width: 8px; height: 8px;
  border-radius: 50%;
}
.feature-ring-move {
  bottom: 58px; left: 28px;
  background: #fa114f;
  box-shadow:
    0 0 4px color-mix(in srgb, #fa114f 90%, transparent),
    0 0 8px color-mix(in srgb, #fa114f 50%, transparent);
}
.feature-ring-exercise {
  bottom: 44px; left: 40px;
  background: #92e82a;
  box-shadow:
    0 0 4px color-mix(in srgb, #92e82a 90%, transparent),
    0 0 8px color-mix(in srgb, #92e82a 50%, transparent);
}
.feature-ring-stand {
  bottom: 34px; left: 56px;
  background: #1cd4d9;
  box-shadow:
    0 0 4px color-mix(in srgb, #1cd4d9 90%, transparent),
    0 0 8px color-mix(in srgb, #1cd4d9 50%, transparent);
}

/* All-rings-closed achievement sparkle — white core with the three
   ring colors echoed in the halo (CalendarRingDots.swift's "white +
   RGB halos when all three close"). Sits below the ring dots. */
.feature-achieve {
  position: absolute;
  bottom: 16px; left: 18px;
  width: 18px; height: 18px;
  fill: #ffffff;
  filter:
    drop-shadow(0 0 3px rgba(255,255,255,0.95))
    drop-shadow(0 0 6px color-mix(in srgb, #fa114f 55%, transparent))
    drop-shadow(0 0 9px color-mix(in srgb, #92e82a 35%, transparent))
    drop-shadow(0 0 12px color-mix(in srgb, #1cd4d9 30%, transparent));
}

/* Evening moon lower-right — crescent silhouette, dim slate so it
   reads as the routine indicator without competing with the centre. */
.feature-moon {
  position: absolute;
  bottom: 16px; right: 16px;
  width: 22px; height: 22px;
  color: #9ea3c7;
  fill: currentColor;
  opacity: 0.7;
  filter:
    drop-shadow(0 0 2px color-mix(in srgb, #9ea3c7 60%, transparent))
    drop-shadow(0 0 5px color-mix(in srgb, #9ea3c7 30%, transparent));
}

/* Celestial fly-by finale */
.craft-finale {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.75rem, 5vw, 2.75rem);
}
.flyby-btn {
  margin: 0; padding: 0; border: 0; background: none;
  cursor: pointer; border-radius: 50%;
  outline: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.2s var(--ease);
}
/* Keep the focus ring for keyboard users; suppress it after a click
   (which is what was flashing the rectangular outline across the
   fly-by animation). */
.flyby-btn:focus { outline: none; }
.flyby-btn:focus-visible { outline: 2px solid color-mix(in srgb, var(--accent) 70%, transparent); outline-offset: 4px; border-radius: 50%; }
.flyby-btn:active { transform: scale(0.985); }
.fly-canvas { display: block; width: clamp(248px, 58vw, 330px); height: clamp(248px, 58vw, 330px); }

/* Mobile: tighten paddings, shrink the readout, let the tagline use
   the full available width, and stack the footer so nothing clips
   off the right edge at narrow viewports. Confirmed bug at 390px:
   the header readout, the hero tagline, and the footer nav were
   running past the right edge under body{overflow-x:hidden}. */
@media (max-width: 480px) {
  .bar {
    padding: 1.25rem 1rem;
    gap: 0.6rem;
    min-width: 0;
  }
  .wordmark {
    font-size: 0.9rem;
    flex-shrink: 0;
  }
  .readout {
    font-size: 0.6rem;
    letter-spacing: 0.14em;
    /* If even shrunk it still wouldn't fit, hide the seconds part
       gracefully — the phase label alone communicates the moment. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .hero {
    padding: clamp(2rem, 8vh, 6rem) 1rem;
    gap: 0.9rem;
  }
  .hero h1 {
    font-size: clamp(2.2rem, 11vw, 5rem);
  }
  .tagline {
    font-size: 0.98rem;
    max-width: 100%;
    padding: 0 0.25rem;
  }
  .about {
    font-size: 0.92rem;
    max-width: 100%;
    padding: 0 0.5rem;
    line-height: 1.6;
  }
  .slider-hint { font-size: 0.58rem; letter-spacing: 0.18em; }
  .craft-teaser { margin-top: 2rem; font-size: 0.78rem; }
  .atmosphere {
    width: min(280px, calc(100vw - 2.5rem));
    margin-top: 1.8rem;
  }
  .foot {
    padding: 1.3rem 1rem 1.6rem;
    justify-content: center;
    text-align: center;
    flex-direction: column;
    gap: 0.7rem;
  }
  .foot nav {
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
  }
  .prose h1 { font-size: clamp(1.7rem, 7vw, 2.6rem); }
}

/* --- App showcase (the fly-by clip + time-of-day strip) -----------
   Sits below the hero; same warm tokens so it reads as one page that
   drifts with the palette. */
.showcase {
  width: 100%;
  max-width: 980px;
  margin: 0 auto;
  padding: clamp(2.5rem, 9vh, 5.5rem) 1.25rem clamp(0.5rem, 3vh, 1.5rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.75rem, 5vh, 3.25rem);
}
.showcase-eyebrow {
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--contrast-ink-soft);
  text-align: center;
  transition: color 1.2s var(--ease);
}
.showcase-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(1.5rem, 5vw, 3.25rem);
}
/* A/B pair: caption above, the two devices side by side on one row.
   The devices are sized with `min(264px, 44vw)` so two always fit a
   single row at any width (down to phones) without wrapping. */
.showcase-pair {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.25rem, 4vw, 2.25rem);
  width: 100%;
}
.showcase-pair .devices {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(0.75rem, 3vw, 2rem);
}
.showcase-pair .device { --w: min(264px, 44vw); }
.device-fig {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
}
.device-label {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--contrast-ink-soft);
  transition: color 1.2s var(--ease);
}
.showcase-caption {
  max-width: 20em;
  font-size: 1rem;
  line-height: 1.55;
  /* contrast-ink-soft (not raw --ink-soft) so the body copy stays
     readable through dusk/twilight/pre-dawn transition palettes, where
     the raw ink-soft can land within 0.1 luminance of base. */
  color: var(--contrast-ink-soft);
  text-align: center;
  transition: color 1.2s var(--ease);
}
/* phone bezel around the autoplay loop */
.device {
  --w: clamp(206px, 56vw, 264px);
  flex: none;
  width: var(--w);
  padding: calc(var(--w) * 0.035);
  background: #0c0d12;
  border-radius: calc(var(--w) * 0.165);
  box-shadow:
    0 32px 64px -26px color-mix(in srgb, var(--shadow-deep) 92%, transparent),
    0 10px 22px -12px color-mix(in srgb, var(--shadow-deep) 60%, transparent),
    inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
.device video {
  display: block;
  width: 100%;
  border-radius: calc(var(--w) * 0.13);
}
/* four-up time-of-day strip */
.strip {
  width: 100%;
  max-width: 780px;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.strip img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
  box-shadow: 0 22px 54px -30px color-mix(in srgb, var(--shadow-deep) 92%, transparent);
}

/* Stillness for those who ask for it: the phase still sets the colours
   at load, it just doesn't drift. */
@media (prefers-reduced-motion: reduce) {
  .glow-orb, .orbit, .cta, .icon, .dial, .atmosphere, .craft-canvas-btn { transition: none; }
  .cta:hover { transform: none; }
}
