cat << 'PYEOF' > /home/claude/build.py

import base64


with open('/mnt/user-data/uploads/IMG_4742.jpeg', 'rb') as f:

    img_data = base64.b64encode(f.read()).decode('utf-8')


html = f'''<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>AJ Niwas — Our Home, Our World</title>

<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;1,300;1,400&family=Cinzel+Decorative:wght@400;700&display=swap" rel="stylesheet">

<style>

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


:root {{

  --cream: #faf6f0;

  --warm: #f5ede0;

  --blush: #e8d5c0;

  --terracotta: #c4724a;

  --rust: #a0522d;

  --forest: #3d5a3e;

  --sage: #7a9e7e;

  --gold: #b8860b;

  --gold-light: #d4a843;

  --ink: #2a1f14;

  --soft: #6b5744;

  --white: #ffffff;

}}


html {{ scroll-behavior: smooth; }}


body {{

  font-family: 'Cormorant Garamond', serif;

  background: var(--cream);

  color: var(--ink);

  overflow-x: hidden;

}}


/* ===== NAV ===== */

nav {{

  position: fixed;

  top: 0; left: 0; right: 0;

  z-index: 100;

  background: rgba(250,246,240,0.92);

  backdrop-filter: blur(12px);

  border-bottom: 1px solid rgba(184,134,11,0.2);

  display: flex;

  justify-content: center;

  gap: clamp(16px, 4vw, 48px);

  padding: 14px 20px;

}}


nav a {{

  font-family: 'Cinzel Decorative', cursive;

  font-size: clamp(0.45rem, 1.2vw, 0.62rem);

  letter-spacing: 0.2em;

  color: var(--soft);

  text-decoration: none;

  text-transform: uppercase;

  transition: color 0.3s;

  white-space: nowrap;

}}

nav a:hover {{ color: var(--terracotta); }}


/* ===== HERO ===== */

.hero {{

  position: relative;

  height: 100vh;

  min-height: 600px;

  display: flex;

  align-items: flex-end;

  justify-content: center;

  overflow: hidden;

}}


.hero-img {{

  position: absolute;

  inset: 0;

  background: url('data:image/jpeg;base64,{img_data}') center center / cover no-repeat;

}}


.hero-overlay {{

  position: absolute;

  inset: 0;

  background: linear-gradient(

    to bottom,

    rgba(0,0,0,0.1) 0%,

    rgba(0,0,0,0.05) 40%,

    rgba(20,10,5,0.7) 75%,

    rgba(20,10,5,0.92) 100%

  );

}}


.hero-content {{

  position: relative;

  z-index: 2;

  text-align: center;

  padding: 0 20px 60px;

  animation: fadeUp 1.4s ease both;

}}


@keyframes fadeUp {{

  from {{ opacity: 0; transform: translateY(30px); }}

  to   {{ opacity: 1; transform: translateY(0); }}

}}


.hero-eyebrow {{

  font-family: 'Cinzel Decorative', cursive;

  font-size: clamp(0.5rem, 1.5vw, 0.7rem);

  letter-spacing: 0.4em;

  color: var(--gold-light);

  opacity: 0.9;

  margin-bottom: 12px;

  text-transform: uppercase;

}}


.hero-title {{

  font-family: 'Playfair Display', serif;

  font-size: clamp(2.8rem, 9vw, 6rem);

  font-weight: 700;

  color: var(--white);

  line-height: 1;

  letter-spacing: -0.02em;

  text-shadow: 0 4px 30px rgba(0,0,0,0.4);

  margin-bottom: 16px;

}}


.hero-title span {{

  font-style: italic;

  color: var(--gold-light);

}}


.hero-caption {{

  font-family: 'Cormorant Garamond', serif;

  font-style: italic;

  font-size: clamp(1rem, 2.5vw, 1.4rem);

  color: rgba(255,255,255,0.8);

  letter-spacing: 0.06em;

  font-weight: 300;

}}


.scroll-hint {{

  position: absolute;

  bottom: 20px;

  left: 50%;

  transform: translateX(-50%);

  z-index: 2;

  display: flex;

  flex-direction: column;

  align-items: center;

  gap: 6px;

  opacity: 0.5;

  animation: bounce 2s infinite;

}}


@keyframes bounce {{

  0%, 100% {{ transform: translateX(-50%) translateY(0); }}

  50% {{ transform: translateX(-50%) translateY(6px); }}

}}


.scroll-hint span {{

  font-size: 0.6rem;

  letter-spacing: 0.3em;

  color: white;

  font-family: 'Cinzel Decorative', cursive;

  text-transform: uppercase;

}}


.scroll-arrow {{

  width: 1px;

  height: 30px;

  background: linear-gradient(to bottom, white, transparent);

}}


/* ===== SECTION COMMON ===== */

section {{

  padding: 80px 20px;

}}


.section-header {{

  text-align: center;

  margin-bottom: 50px;

}}


.section-eyebrow {{

  font-family: 'Cinzel Decorative', cursive;

  font-size: clamp(0.45rem, 1.2vw, 0.6rem);

  letter-spacing: 0.4em;

  color: var(--terracotta);

  text-transform: uppercase;

  margin-bottom: 10px;

}}


.section-title {{

  font-family: 'Playfair Display', serif;

  font-size: clamp(1.8rem, 5vw, 3rem);

  font-weight: 600;

  color: var(--ink);

  line-height: 1.1;

}}


.section-title em {{ font-style: italic; color: var(--terracotta); }}


.divider {{

  display: flex;

  align-items: center;

  justify-content: center;

  gap: 12px;

  margin: 16px auto 0;

  opacity: 0.4;

}}

.divider::before, .divider::after {{

  content: '';

  width: 60px;

  height: 1px;

  background: var(--gold);

}}

.divider-symbol {{ color: var(--gold); font-size: 0.8rem; }}


/* ===== CALENDAR ===== */

#calendar {{ background: var(--warm); }}


.calendar-grid {{

  display: grid;

  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));

  gap: 20px;

  max-width: 1100px;

  margin: 0 auto;

}}


.month-card {{

  background: var(--white);

  border-radius: 16px;

  overflow: hidden;

  box-shadow: 0 2px 20px rgba(42,31,20,0.08);

  transition: transform 0.3s ease, box-shadow 0.3s ease;

  border: 1px solid rgba(184,134,11,0.12);

}}


.month-card:hover {{

  transform: translateY(-4px);

  box-shadow: 0 8px 40px rgba(42,31,20,0.14);

}}


.month-card.current-month {{

  border: 2px solid var(--terracotta);

  box-shadow: 0 4px 30px rgba(196,114,74,0.2);

}}


.month-header {{

  padding: 16px 20px 12px;

  background: linear-gradient(135deg, var(--forest) 0%, #2d4a2e 100%);

  display: flex;

  align-items: center;

  justify-content: space-between;

}}


.month-card.current-month .month-header {{

  background: linear-gradient(135deg, var(--terracotta) 0%, var(--rust) 100%);

}}


.month-name {{

  font-family: 'Playfair Display', serif;

  font-size: 1.1rem;

  font-weight: 700;

  color: white;

  letter-spacing: 0.05em;

}}


.month-icon {{ font-size: 1.3rem; }}


.month-events {{

  padding: 14px 20px 18px;

  display: flex;

  flex-direction: column;

  gap: 8px;

}}


.event-item {{

  display: flex;

  align-items: flex-start;

  gap: 10px;

  font-size: 0.92rem;

  color: var(--soft);

  font-family: 'Cormorant Garamond', serif;

  line-height: 1.3;

}}


.event-dot {{

  width: 6px;

  height: 6px;

  border-radius: 50%;

  background: var(--gold);

  flex-shrink: 0;

  margin-top: 5px;

}}


.event-item.special .event-dot {{ background: var(--terracotta); }}

.event-item.family .event-dot {{ background: var(--forest); }}


/* ===== DATE NIGHT 8-BALL ===== */

#datenight {{ background: #0a0a12; }}


#datenight .section-title {{ color: white; }}

#datenight .section-eyebrow {{ color: #b06bff; }}

#datenight .divider-symbol {{ color: #b06bff; }}

#datenight .divider::before, #datenight .divider::after {{ background: #b06bff; }}


.ball-wrap {{

  display: flex;

  flex-direction: column;

  align-items: center;

  gap: 24px;

}}


.ball-container {{

  position: relative;

  width: clamp(220px, 40vmin, 300px);

  height: clamp(220px, 40vmin, 300px);

  cursor: pointer;

  user-select: none;

}}


.ball-outer {{

  width: 100%; height: 100%;

  border-radius: 50%;

  background: radial-gradient(circle at 35% 30%, #4a2080 0%, #1e0a50 30%, #0d0530 60%, #060218 100%);

  box-shadow: 0 0 0 2px rgba(176,107,255,0.2), 0 0 40px rgba(107,63,160,0.5), 0 0 100px rgba(107,63,160,0.25), inset 0 -20px 60px rgba(0,0,0,0.8), inset 0 10px 30px rgba(176,107,255,0.15);

  display: flex; align-items: center; justify-content: center;

  position: relative;

  transition: box-shadow 0.3s;

}}


.ball-outer::before {{

  content: '';

  position: absolute;

  top: 12%; left: 20%;

  width: 35%; height: 25%;

  background: radial-gradient(ellipse, rgba(255,255,255,0.22) 0%, transparent 70%);

  border-radius: 50%;

  pointer-events: none;

}}


.ball-container:hover .ball-outer {{

  box-shadow: 0 0 0 2px rgba(176,107,255,0.5), 0 0 60px rgba(107,63,160,0.8), 0 0 120px rgba(107,63,160,0.4), inset 0 -20px 60px rgba(0,0,0,0.8);

}}


.ball-window {{

  width: 55%; height: 55%;

  border-radius: 50%;

  background: radial-gradient(circle at 40% 40%, #1a0840 0%, #0a0420 100%);

  border: 1px solid rgba(176,107,255,0.3);

  box-shadow: inset 0 0 20px rgba(0,0,0,0.9), inset 0 0 10px rgba(107,63,160,0.3);

  display: flex; align-items: center; justify-content: center;

  overflow: hidden; position: relative;

}}


.window-text {{

  font-family: 'Cormorant Garamond', serif;

  font-style: italic;

  font-size: clamp(0.5rem, 1.4vw, 0.78rem);

  color: #b06bff;

  text-align: center;

  padding: 8px;

  line-height: 1.3;

  text-shadow: 0 0 10px rgba(176,107,255,0.8), 0 0 25px rgba(176,107,255,0.5);

  opacity: 0;

  transition: opacity 0.8s ease;

}}

.window-text.visible {{ opacity: 1; }}


.eight-sym {{

  font-family: 'Cinzel Decorative', cursive;

  font-size: clamp(1.5rem, 4vw, 2.2rem);

  font-weight: 900;

  color: rgba(200,200,224,0.8);

  transition: opacity 0.3s;

}}

.eight-sym.hidden {{ opacity: 0; }}


.ball-answer {{

  background: rgba(30,10,64,0.7);

  border: 1px solid rgba(176,107,255,0.25);

  border-radius: 16px;

  padding: 18px 32px;

  max-width: min(480px, 90vw);

  text-align: center;

  backdrop-filter: blur(10px);

  min-height: 72px;

  display: flex;

  flex-direction: column;

  align-items: center;

  justify-content: center;

  gap: 6px;

  transition: opacity 0.5s, background 0.8s, border-color 0.8s;

  opacity: 0;

}}

.ball-answer.visible {{ opacity: 1; }}


.answer-label {{

  font-family: 'Cinzel Decorative', cursive;

  font-size: 0.55rem;

  letter-spacing: 0.3em;

  color: #d4a843;

  opacity: 0.7;

  text-transform: uppercase;

}}


.answer-text {{

  font-family: 'Playfair Display', serif;

  font-size: clamp(1rem, 2.5vw, 1.3rem);

  font-weight: 600;

  color: white;

  letter-spacing: 0.03em;

  line-height: 1.3;

}}


.tap-hint {{

  font-family: 'Cormorant Garamond', serif;

  font-style: italic;

  font-size: clamp(0.8rem, 2vw, 1rem);

  color: rgba(200,180,255,0.5);

  letter-spacing: 0.1em;

}}


.all-ideas-btn {{

  background: none;

  border: 1px solid rgba(176,107,255,0.3);

  border-radius: 24px;

  padding: 8px 24px;

  color: rgba(176,107,255,0.6);

  font-family: 'Cinzel Decorative', cursive;

  font-size: 0.5rem;

  letter-spacing: 0.2em;

  cursor: pointer;

  transition: all 0.3s;

  text-transform: uppercase;

}}

.all-ideas-btn:hover {{ border-color: rgba(176,107,255,0.7); color: rgba(176,107,255,0.9); }}


@keyframes shake {{

  0%   {{ transform: translate(0,0) rotate(0deg); }}

  10%  {{ transform: translate(-6px,-4px) rotate(-3deg); }}

  20%  {{ transform: translate(6px,4px) rotate(3deg); }}

  30%  {{ transform: translate(-5px,6px) rotate(-2deg); }}

  40%  {{ transform: translate(5px,-5px) rotate(2deg); }}

  50%  {{ transform: translate(-4px,4px) rotate(-4deg); }}

  60%  {{ transform: translate(4px,-4px) rotate(3deg); }}

  70%  {{ transform: translate(-5px,3px) rotate(-2deg); }}

  80%  {{ transform: translate(5px,5px) rotate(2deg); }}

  90%  {{ transform: translate(-3px,-3px) rotate(-1deg); }}

  100% {{ transform: translate(0,0) rotate(0deg); }}

}}


@keyframes floatBall {{

  0%,100% {{ transform: translateY(0); }}

  50% {{ transform: translateY(-10px); }}

}}


.ball-outer.floating {{ animation: floatBall 4s ease-in-out infinite; }}

.ball-outer.shaking  {{ animation: shake 0.7s ease-in-out; }}


@keyframes ripple {{

  0%   {{ transform: scale(0.95); opacity: 0.8; }}

  100% {{ transform: scale(1.6); opacity: 0; }}

}}

.ball-ripple {{

  position: absolute; inset: 0;

  border-radius: 50%;

  border: 2px solid rgba(176,107,255,0.6);

  animation: ripple 1s ease-out forwards;

  pointer-events: none;

}}


/* ===== IDEAS PANEL ===== */

.ideas-panel {{

  position: fixed; inset: 0; z-index: 200;

  background: rgba(6,2,24,0.97);

  display: flex; flex-direction: column; align-items: center;

  padding: 50px 20px 40px;

  overflow-y: auto;

  opacity: 0; pointer-events: none;

  transition: opacity 0.4s;

}}

.ideas-panel.open {{ opacity: 1; pointer-events: all; }}

.ideas-panel h2 {{

  font-family: 'Playfair Display', serif;

  font-size: clamp(1.2rem, 3vw, 1.8rem);

  color: #d4a843;

  margin-bottom: 28px;

  font-style: italic;

}}

.ideas-grid {{

  display: grid;

  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

  gap: 10px; max-width: 800px; width: 100%;

}}

.idea-chip {{

  background: rgba(30,16,64,0.8);

  border: 1px solid rgba(176,107,255,0.2);

  border-radius: 8px; padding: 10px 16px;

  font-family: 'Cormorant Garamond', serif;

  font-size: 0.95rem; color: #c8c8e0; text-align: center;

}}

.close-panel {{

  margin-top: 28px; padding: 10px 32px;

  background: rgba(107,63,160,0.3);

  border: 1px solid rgba(176,107,255,0.4);

  border-radius: 24px; color: white;

  font-family: 'Cinzel Decorative', cursive;

  font-size: 0.55rem; letter-spacing: 0.2em;

  cursor: pointer; transition: background 0.2s;

}}

.close-panel:hover {{ background: rgba(107,63,160,0.6); }}


/* ===== CHORE WHEEL ===== */

#chores {{ background: var(--cream); }}


.wheel-section {{

  display: flex;

  flex-direction: column;

  align-items: center;

  gap: 30px;

  max-width: 700px;

  margin: 0 auto;

}}


.wheel-wrap {{

  position: relative;

  width: clamp(280px, 60vw, 420px);

  height: clamp(280px, 60vw, 420px);

}}


canvas#choreWheel {{

  width: 100%;

  height: 100%;

  border-radius: 50%;

  box-shadow: 0 8px 40px rgba(42,31,20,0.2);

}}


.wheel-pointer {{

  position: absolute;

  top: 50%;

  left: 50%;

  transform: translate(-50%, -50%);

  width: 22px;

  height: 22px;

  background: white;

  border: 3px solid var(--terracotta);

  border-radius: 50%;

  box-shadow: 0 0 0 4px rgba(196,114,74,0.3);

  z-index: 5;

  cursor: pointer;

}}


.spin-btn {{

  padding: 14px 48px;

  background: linear-gradient(135deg, var(--terracotta) 0%, var(--rust) 100%);

  border: none; border-radius: 50px;

  color: white;

  font-family: 'Cinzel Decorative', cursive;

  font-size: clamp(0.55rem, 1.5vw, 0.7rem);

  letter-spacing: 0.2em;

  cursor: pointer;

  box-shadow: 0 4px 20px rgba(196,114,74,0.4);

  transition: transform 0.2s, box-shadow 0.2s;

  text-transform: uppercase;

}}

.spin-btn:hover {{ transform: translateY(-2px); box-shadow: 0 8px 30px rgba(196,114,74,0.5); }}

.spin-btn:active {{ transform: scale(0.97); }}


.chore-result {{

  background: var(--white);

  border: 2px solid var(--terracotta);

  border-radius: 16px;

  padding: 20px 36px;

  text-align: center;

  min-width: 260px;

  opacity: 0;

  transition: opacity 0.5s;

}}

.chore-result.visible {{ opacity: 1; }}

.chore-result-label {{

  font-family: 'Cinzel Decorative', cursive;

  font-size: 0.55rem;

  letter-spacing: 0.3em;

  color: var(--terracotta);

  text-transform: uppercase;

  margin-bottom: 8px;

}}

.chore-result-text {{

  font-family: 'Playfair Display', serif;

  font-size: 1.4rem;

  font-weight: 700;

  color: var(--ink);

}}


/* ===== PHOTO BOOTH ===== */

#photobooth {{ background: var(--warm); }}


.photobooth-wrap {{

  max-width: 700px;

  margin: 0 auto;

  display: flex;

  flex-direction: column;

  gap: 24px;

}}


.upload-zone {{

  border: 2px dashed rgba(196,114,74,0.4);

  border-radius: 20px;

  padding: 50px 30px;

  text-align: center;

  cursor: pointer;

  transition: border-color 0.3s, background 0.3s;

  background: rgba(255,255,255,0.5);

  position: relative;

  overflow: hidden;

}}

.upload-zone:hover {{ border-color: var(--terracotta); background: rgba(255,255,255,0.8); }}


.upload-zone input[type=file] {{

  position: absolute; inset: 0;

  opacity: 0; cursor: pointer;

  width: 100%; height: 100%;

}}


.upload-icon {{ font-size: 2.5rem; margin-bottom: 12px; }}

.upload-label {{

  font-family: 'Playfair Display', serif;

  font-size: 1.1rem;

  color: var(--soft);

  font-style: italic;

}}

.upload-sub {{

  font-size: 0.85rem;

  color: var(--blush);

  margin-top: 6px;

  font-family: 'Cormorant Garamond', serif;

}}


.preview-img {{

  width: 100%;

  border-radius: 16px;

  object-fit: cover;

  max-height: 400px;

  display: none;

  box-shadow: 0 8px 40px rgba(42,31,20,0.15);

}}


.memory-input {{

  width: 100%;

  border: 1px solid rgba(196,114,74,0.3);

  border-radius: 12px;

  padding: 16px 20px;

  font-family: 'Cormorant Garamond', serif;

  font-size: 1.05rem;

  color: var(--ink);

  background: white;

  resize: vertical;

  min-height: 100px;

  outline: none;

  transition: border-color 0.3s;

  font-style: italic;

}}

.memory-input:focus {{ border-color: var(--terracotta); }}

.memory-input::placeholder {{ color: var(--blush); }}


.save-memory-btn {{

  align-self: center;

  padding: 13px 44px;

  background: linear-gradient(135deg, var(--forest) 0%, #2d4a2e 100%);

  border: none; border-radius: 50px;

  color: white;

  font-family: 'Cinzel Decorative', cursive;

  font-size: 0.58rem;

  letter-spacing: 0.2em;

  cursor: pointer;

  box-shadow: 0 4px 20px rgba(61,90,62,0.3);

  transition: transform 0.2s, box-shadow 0.2s;

  text-transform: uppercase;

}}

.save-memory-btn:hover {{ transform: translateY(-2px); box-shadow: 0 8px 30px rgba(61,90,62,0.4); }}


.memories-gallery {{

  display: grid;

  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

  gap: 16px;

  margin-top: 20px;

}}


.memory-card {{

  background: white;

  border-radius: 16px;

  overflow: hidden;

  box-shadow: 0 4px 20px rgba(42,31,20,0.1);

  transition: transform 0.3s;

}}

.memory-card:hover {{ transform: translateY(-4px); }}

.memory-card img {{ width: 100%; height: 180px; object-fit: cover; }}

.memory-card-msg {{

  padding: 12px 14px;

  font-family: 'Cormorant Garamond', serif;

  font-style: italic;

  font-size: 0.95rem;

  color: var(--soft);

  line-height: 1.4;

}}

.memory-card-date {{

  padding: 0 14px 12px;

  font-size: 0.75rem;

  color: var(--blush);

  font-family: 'Cormorant Garamond', serif;

}}


/* ===== FOOTER ===== */

footer {{

  background: var(--ink);

  color: rgba(255,255,255,0.4);

  text-align: center;

  padding: 30px 20px;

  font-family: 'Cormorant Garamond', serif;

  font-size: 0.9rem;

  letter-spacing: 0.1em;

}}

footer span {{ color: var(--terracotta); }}

</style>

</head>

<body>


<!-- NAV -->

<nav>

  <a href="#home">Home</a>

  <a href="#calendar">Calendar</a>

  <a href="#datenight">Date Night</a>

  <a href="#chores">Chore Wheel</a>

  <a href="#photobooth">Photo Booth</a>

</nav>


<!-- HERO -->

<section id="home" class="hero">

  <div class="hero-img"></div>

  <div class="hero-overlay"></div>

  <div class="hero-content">

    <div class="hero-eyebrow">est. our forever</div>

    <h1 class="hero-title">Welcome to <span>AJ Niwas</span></h1>

    <p class="hero-caption">building life, one memory at a time </p>

  </div>

  <div class="scroll-hint">

    <span>explore</span>

    <div class="scroll-arrow"></div>

  </div>

</section>


<!-- CALENDAR -->

<section id="calendar">

  <div class="section-header">

    <div class="section-eyebrow">our year</div>

    <h2 class="section-title">The <em>Family</em> Calendar</h2>

    <div class="divider"><span class="divider-symbol"></span></div>

  </div>

  <div class="calendar-grid" id="calendarGrid"></div>

</section>


<!-- DATE NIGHT -->

<section id="datenight">

  <div class="section-header">

    <div class="section-eyebrow">the oracle decides</div>

    <h2 class="section-title" style="color:white;">Date Night <em style="color:#b06bff;">Magic</em></h2>

    <div class="divider"><span class="divider-symbol"></span></div>

  </div>

  <div class="ball-wrap">

    <div class="ball-container" id="ballContainer" onclick="shakeBall()" title="Tap to reveal tonight's plan">

      <div class="ball-outer floating" id="ballOuter">

        <div class="ball-window">

          <div class="eight-sym" id="eightSym">8</div>

          <div class="window-text" id="windowText"></div>

        </div>

      </div>

    </div>

    <p class="tap-hint" id="tapHint">tap the oracle to reveal your fate</p>

    <div class="ball-answer" id="ballAnswer">

      <div class="answer-label">Tonight's Destiny</div>

      <div class="answer-text" id="answerText"></div>

    </div>

    <button class="all-ideas-btn" onclick="openIdeas()">view all possibilities</button>

  </div>

</section>


<!-- CHORE WHEEL -->

<section id="chores">

  <div class="section-header">

    <div class="section-eyebrow">who does what</div>

    <h2 class="section-title">The <em>Chore</em> Wheel</h2>

    <div class="divider"><span class="divider-symbol"></span></div>

  </div>

  <div class="wheel-section">

    <div class="wheel-wrap">

      <canvas id="choreWheel" width="420" height="420"></canvas>

      <div class="wheel-pointer" id="wheelPointer"></div>

    </div>

    <button class="spin-btn" onclick="spinWheel()"> Spin the Wheel </button>

    <div class="chore-result" id="choreResult">

      <div class="chore-result-label">Today's Chore</div>

      <div class="chore-result-text" id="choreResultText"></div>

    </div>

  </div>

</section>


<!-- PHOTO BOOTH -->

<section id="photobooth">

  <div class="section-header">

    <div class="section-eyebrow">capture the moment</div>

    <h2 class="section-title">Our <em>Photo Booth</em></h2>

    <div class="divider"><span class="divider-symbol"></span></div>

  </div>

  <div class="photobooth-wrap">

    <div class="upload-zone" id="uploadZone">

      <input type="file" accept="image/*" id="photoInput" onchange="handlePhoto(event)">

      <div class="upload-icon">📸</div>

      <div class="upload-label">Tap to upload today's memory</div>

      <div class="upload-sub">any photo from your heart</div>

    </div>

    <img id="previewImg" class="preview-img" alt="Preview">

    <textarea class="memory-input" id="memoryMsg" placeholder="write something sweet about this moment..."></textarea>

    <button class="save-memory-btn" onclick="saveMemory()"> Save This Memory </button>

    <div class="memories-gallery" id="memoriesGallery"></div>

  </div>

</section>


<!-- FOOTER -->

<footer>

  <p>Made with <span></span> for AJ Niwas &nbsp;·&nbsp; Our little corner of the world</p>

</footer>


<!-- IDEAS PANEL -->

<div class="ideas-panel" id="ideasPanel">

  <h2>All Date Night Possibilities</h2>

  <div class="ideas-grid" id="ideasGrid"></div>

  <button class="close-panel" onclick="closeIdeas()">close</button>

</div>


<script>

// ===== CALENDAR =====

const months = [

  {{ name:"January", icon:"🎆", events:[

    {{text:"New Year", type:"special"}},

    {{text:"Lohri", type:"family"}},

    {{text:"Makar Sankranti", type:"family"}}

  ]}},

  {{ name:"February", icon:"💕", events:[

    {{text:"Uttarayan / Vasant Panchami", type:"family"}},

    {{text:"Nini's Birthday 🎂", type:"special"}},

    {{text:"Valentine's Day", type:"special"}},

    {{text:"Family Day", type:"family"}},

    {{text:"St. Patrick's Day", type:""}}

  ]}},

  {{ name:"March", icon:"🌸", events:[

    {{text:"Navratri & Ram Navami", type:"family"}},

    {{text:"Holi 🎨", type:"special"}},

    {{text:"Jasmine's Birthday 🎂", type:"special"}}

  ]}},

  {{ name:"April", icon:"🐣", events:[

    {{text:"Arth's Birthday 🎂", type:"special"}},

    {{text:"Easter", type:"family"}},

    {{text:"Vaisakhi — Gardening Day 🌱", type:"family"}}

  ]}},

  {{ name:"May", icon:"🌷", events:[

    {{text:"Cherry Blossoms 🌸", type:"family"}},

    {{text:"Tulip Festival 🌷", type:"family"}},

    {{text:"Spring Cleaning 🧹", type:""}},

    {{text:"Mother's Day 💐", type:"special"}}

  ]}},

  {{ name:"June", icon:"☀️", events:[

    {{text:"Father's Day — BBQ Day 🍖", type:"special"}},

    {{text:"Drive-In Movie Night 🎬", type:"family"}}

  ]}},

  {{ name:"July", icon:"🍁", events:[

    {{text:"Canada Day 🎇", type:"special"}}

  ]}},

  {{ name:"August", icon:"🍎", events:[

    {{text:"Raksha Bandhan", type:"family"}},

    {{text:"Apple Picking Season 🍎", type:"family"}}

  ]}},

  {{ name:"September", icon:"🌙", events:[

    {{text:"Janmashtami", type:"family"}},

    {{text:"Ganesh Chaturthi", type:"family"}}

  ]}},

  {{ name:"October", icon:"🎃", events:[

    {{text:"Dussehra", type:"family"}},

    {{text:"Halloween 🎃", type:"special"}},

    {{text:"Navratri", type:"family"}},

    {{text:"Thanksgiving 🦃", type:"special"}}

  ]}},

  {{ name:"November", icon:"🪔", events:[

    {{text:"Diwali 🪔", type:"special"}},

    {{text:"Bandi Chor Divas", type:"family"}},

    {{text:"Gujarati New Year", type:"family"}},

    {{text:"Day of the Dead", type:""}}

  ]}},

  {{ name:"December", icon:"🎄", events:[

    {{text:"Christmas 🎄", type:"special"}}

  ]}}

];


const currentMonth = new Date().getMonth();

const grid = document.getElementById('calendarGrid');

months.forEach((m, i) => {{

  const card = document.createElement('div');

  card.className = 'month-card' + (i === currentMonth ? ' current-month' : '');

  card.innerHTML = `

    <div class="month-header">

      <span class="month-name">${{m.name}}</span>

      <span class="month-icon">${{m.icon}}</span>

    </div>

    <div class="month-events">

      ${{m.events.map(e => `<div class="event-item ${{e.type}}"><div class="event-dot"></div><span>${{e.text}}</span></div>`).join('')}}

    </div>`;

  grid.appendChild(card);

}});


// ===== DATE NIGHT BALL =====

const ideas = [

  "Indoor Camping 🏕️","Indoor Picnic 🧺","Become a Bartender 🍹","Home Clubbing 🪩",

  "Movie Night after Nini sleeps 🎬","Spa Night at Home 🧖","Hibachi at Home 🔥","Sunset Walks 🌅",

  "Paint Nite with Nini 🎨","Dance Night 💃","Recreate Concert Vibes 🎸","Shaadi ka Buffet Night 🍽️",

  "Funky Photoshoot 📸","Sofa Pit with Pillows 🛋️","Muted Movie Dialogues 🤫","Backchod Reel Day 📱",

  "Snapchat Filters 😜","Cardboard Craft Night 📦","Clay Date 🏺","Backyard High Tea Party 🫖",

  "Random YouTube Night 📺","Casino Night 🃏","Wings & Beer Night 🍗🍺","Table Tennis Night 🏓",

  "Recreate Childhood Memories 🌟","Podcast Night with Agenda 🎙️","Beads Night 📿","Casio Night 🎹",

  "Calling Friends Night 📞","Mock Drill Night 🚨","Bar Trivia Night 🧠","Fashion Show 👗",

  "Old Familiar Shows 📡","Horror Movie Night 👻","Sleep at Sunrise 🌄","Theme Party Night 🎭",

  "Book Club Night 📚","Doodle Night ✏️","Roleplay Night 🎭","Recipe Video Night 🍳",

  "Vacation Planning Night ✈️","DIY Video Night 🔨","Business Idea Night 💡","AI Creation Night 🤖",

  "Deep Dive One Topic Night 🔭","Takeout Night 🥡"

];


const ballColors = [

  {{bg:'rgba(30,10,64,0.7)', border:'rgba(176,107,255,0.3)', text:'#b06bff'}},

  {{bg:'rgba(10,40,20,0.7)', border:'rgba(100,200,100,0.3)', text:'#7acc7a'}},

  {{bg:'rgba(60,15,15,0.7)', border:'rgba(220,100,100,0.3)', text:'#e87070'}},

  {{bg:'rgba(10,30,60,0.7)', border:'rgba(80,150,255,0.3)', text:'#70aaff'}},

  {{bg:'rgba(60,40,0,0.7)', border:'rgba(220,180,50,0.3)', text:'#e8c050'}},

  {{bg:'rgba(40,10,50,0.7)', border:'rgba(200,80,220,0.3)', text:'#d060e0'}},

];


const windowPhrases = ["the stars align...","destiny speaks...","it is written...","the cosmos decree...","so it shall be...","the fates decide..."];

let isShaking = false;


function shakeBall() {{

  if (isShaking) return;

  isShaking = true;

  const ball = document.getElementById('ballOuter');

  const eightSym = document.getElementById('eightSym');

  const winText = document.getElementById('windowText');

  const answer = document.getElementById('ballAnswer');

  const ansText = document.getElementById('answerText');


  ball.classList.remove('floating');

  ball.classList.add('shaking');

  winText.classList.remove('visible');

  eightSym.classList.remove('hidden');

  answer.classList.remove('visible');


  const rip = document.createElement('div');

  rip.className = 'ball-ripple';

  document.getElementById('ballContainer').appendChild(rip);

  setTimeout(() => rip.remove(), 1050);


  setTimeout(() => {{

    eightSym.classList.add('hidden');

    winText.textContent = windowPhrases[Math.floor(Math.random()*windowPhrases.length)];

    winText.classList.add('visible');

  }}, 500);


  setTimeout(() => {{

    const pick = ideas[Math.floor(Math.random()*ideas.length)];

    const col = ballColors[Math.floor(Math.random()*ballColors.length)];

    winText.textContent = pick;

    ansText.textContent = pick;

    answer.style.background = col.bg;

    answer.style.borderColor = col.border;

    ansText.style.color = 'white';

    answer.classList.add('visible');

    document.getElementById('tapHint').textContent = 'tap again to seek another fate';

  }}, 1400);


  setTimeout(() => {{

    ball.classList.remove('shaking');

    ball.classList.add('floating');

    isShaking = false;

  }}, 800);

}}


const igrid = document.getElementById('ideasGrid');

ideas.forEach(idea => {{

  const c = document.createElement('div');

  c.className = 'idea-chip';

  c.textContent = idea;

  igrid.appendChild(c);

}});


function openIdeas() {{ document.getElementById('ideasPanel').classList.add('open'); }}

function closeIdeas() {{ document.getElementById('ideasPanel').classList.remove('open'); }}


// ===== CHORE WHEEL =====

const chores = [

  "Bedrooms 🛏️","Bathrooms 🚿","Kitchen 🍳","Living & Dining 🛋️",

  "Fridge 🥶","Oven 🔥","Windows 🪟","Laundry Room 🧺",

  "Backyard 🌿","Garage 🚗","Car 🚙","Drawers 🗂️"

];


const choreColors = [

  '#c4724a','#3d5a3e','#b8860b','#7a9e7e','#a0522d','#5a7a5e',

  '#d4883a','#4d6e4e','#c49020','#8aae8e','#b06030','#6d8e6e'

];


let wheelAngle = 0;

let isSpinning = false;


function drawWheel() {{

  const canvas = document.getElementById('choreWheel');

  const ctx = canvas.getContext('2d');

  const cx = canvas.width/2, cy = canvas.height/2, r = cx - 10;

  const sliceAngle = (2*Math.PI)/chores.length;


  ctx.clearRect(0,0,canvas.width,canvas.height);


  chores.forEach((chore, i) => {{

    const start = wheelAngle + i*sliceAngle;

    const end = start + sliceAngle;

    ctx.beginPath();

    ctx.moveTo(cx,cy);

    ctx.arc(cx,cy,r,start,end);

    ctx.closePath();

    ctx.fillStyle = choreColors[i];

    ctx.fill();

    ctx.strokeStyle = 'rgba(255,255,255,0.4)';

    ctx.lineWidth = 2;

    ctx.stroke();


    ctx.save();

    ctx.translate(cx,cy);

    ctx.rotate(start + sliceAngle/2);

    ctx.textAlign = 'right';

    ctx.fillStyle = 'white';

    ctx.font = `bold ${{Math.floor(canvas.width * 0.035)}}px Cormorant Garamond, serif`;

    ctx.shadowColor = 'rgba(0,0,0,0.4)';

    ctx.shadowBlur = 4;

    // strip emoji for canvas text

    const label = chore.replace(/[\\uD800-\\uDFFF]./g,'').replace(/[^\\x00-\\x7F]/g,'').trim();

    ctx.fillText(label, r - 14, 5);

    ctx.restore();

  }});


  // Center circle

  ctx.beginPath();

  ctx.arc(cx,cy,24,0,2*Math.PI);

  ctx.fillStyle = 'white';

  ctx.fill();

  ctx.strokeStyle = '#c4724a';

  ctx.lineWidth = 3;

  ctx.stroke();


  // Arrow pointer at top

  ctx.beginPath();

  ctx.moveTo(cx, 2);

  ctx.lineTo(cx-10, 26);

  ctx.lineTo(cx+10, 26);

  ctx.closePath();

  ctx.fillStyle = '#c4724a';

  ctx.fill();

}}


function spinWheel() {{

  if (isSpinning) return;

  isSpinning = true;

  const result = document.getElementById('choreResult');

  result.classList.remove('visible');


  const spins = (5 + Math.random()*5) * 2 * Math.PI;

  const duration = 3000 + Math.random()*1500;

  const start = performance.now();

  const startAngle = wheelAngle;


  function animate(now) {{

    const elapsed = now - start;

    const progress = Math.min(elapsed/duration, 1);

    const ease = 1 - Math.pow(1-progress, 4);

    wheelAngle = startAngle + spins * ease;

    drawWheel();

    if (progress < 1) {{

      requestAnimationFrame(animate);

    }} else {{

      // Find which slice is at top (12 o'clock)

      const sliceAngle = (2*Math.PI)/chores.length;

      const normalized = (((-wheelAngle) % (2*Math.PI)) + 2*Math.PI) % (2*Math.PI);

      const index = Math.floor(normalized/sliceAngle) % chores.length;

      document.getElementById('choreResultText').textContent = chores[index];

      result.classList.add('visible');

      isSpinning = false;

    }}

  }}

  requestAnimationFrame(animate);

}}


drawWheel();


// ===== PHOTO BOOTH =====

let currentPhotoData = null;

const memories = [];


function handlePhoto(e) {{

  const file = e.target.files[0];

  if (!file) return;

  const reader = new FileReader();

  reader.onload = ev => {{

    currentPhotoData = ev.target.result;

    const preview = document.getElementById('previewImg');

    preview.src = currentPhotoData;

    preview.style.display = 'block';

    document.getElementById('uploadZone').style.display = 'none';

  }};

  reader.readAsDataURL(file);

}}


function saveMemory() {{

  if (!currentPhotoData) {{ alert('Please upload a photo first!'); return; }}

  const msg = document.getElementById('memoryMsg').value.trim();

  const date = new Date().toLocaleDateString('en-US', {{month:'long', day:'numeric', year:'numeric'}});

  memories.push({{photo: currentPhotoData, msg: msg || 'A beautiful moment ', date}});

  renderGallery();

  currentPhotoData = null;

  document.getElementById('previewImg').style.display = 'none';

  document.getElementById('uploadZone').style.display = 'block';

  document.getElementById('memoryMsg').value = '';

  document.getElementById('photoInput').value = '';

}}


function renderGallery() {{

  const gallery = document.getElementById('memoriesGallery');

  gallery.innerHTML = '';

  memories.slice().reverse().forEach(m => {{

    const card = document.createElement('div');

    card.className = 'memory-card';

    card.innerHTML = `<img src="${{m.photo}}" alt="memory"><div class="memory-card-msg">${{m.msg}}</div><div class="memory-card-date">${{m.date}}</div>`;

    gallery.appendChild(card);

  }});

}}

</script>

</body>

</html>'''


with open('/mnt/user-data/outputs/index.html', 'w') as f:

    f.write(html)


print("Done! Size:", len(html), "chars")

PYEOF

python3 /home/claude/build.py