top of page

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Puzzle Calendar (3‑Day Demo)</title>
<style>
  :root {
    --bg: radial-gradient(1200px 600px at 20% -10%, #14315b 0%, #0a1a33 50%, #040a18 100%);
    --gold: #d4af37;
    --gold-soft:#e6c766;
    --cream: #fff8e6;
    --card: rgba(255,255,255,0.06);
    --card-2: rgba(255,255,255,0.12);
    --glow: 0 0 30px rgba(212,175,55,.25), 0 0 8px rgba(212,175,55,.55) inset;
  }
  html, body {height:100%;}
  body {
    margin:0; font-family: ui-rounded, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", "Segoe UI Emoji";
    color: #eef2ff; background: var(--bg); overflow-x:hidden;
  }
  .sky {
    position: fixed; inset:0; pointer-events:none; z-index: 0;
    background: radial-gradient(800px 400px at 80% -20%, rgba(120,190,255,.15), transparent 60%),
                radial-gradient(600px 300px at 10% 120%, rgba(150,220,255,.10), transparent 60%);
  }
  .twinkle { position:absolute; width:2px; height:2px; background:#cfe8ff; border-radius:50%; opacity:.9; box-shadow:0 0 8px 2px rgba(255,255,255,.7)}
  .container { position:relative; z-index:1; max-width:1100px; margin: 32px auto 80px; padding: 0 16px; }
  header { text-align:center; margin: 24px 0 10px; }
  .title {
    font-size: clamp(28px, 4vw, 48px);
    line-height:1.1; letter-spacing: .5px; margin: 0;
    background: linear-gradient(180deg, var(--gold), var(--gold-soft));
    -webkit-background-clip: text; background-clip:text; color: transparent;
    text-shadow: 0 2px 20px rgba(212,175,55,.2);
  }
  .subtitle { margin:10px 0 0; font-size: clamp(14px, 2.2vw, 18px); color: #dbe7ff; opacity:.9 }
  .ribbon {
    margin:16px auto 26px; width:min(860px, 92%); padding:10px 14px; border:1px solid rgba(255,255,255,.12);
    background: linear-gradient(0deg, rgba(255,255,255,.06), rgba(255,255,255,.08)); border-radius: 14px;
    box-shadow: 0 6px 24px rgba(0,0,0,.25), inset 0 1px 0 rgba(255,255,255,.08);
    text-align:center;
  }

  /* Windows grid */
  .grid { display:grid; grid-template-columns: repeat(3, 1fr); gap:16px; margin: 22px auto; max-width: 860px; }
  @media (min-width: 720px){ .grid{ gap:20px; } }
  .door {
    position:relative; aspect-ratio: 1/1; border-radius: 16px; overflow:hidden; cursor:pointer;
    border: 1px solid rgba(255,255,255,.12); background: var(--card);
    box-shadow: 0 14px 40px rgba(0,0,0,.3);
    transition: transform .2s ease, box-shadow .2s ease;
  }
  .door:focus-visible { outline: 3px solid var(--gold); outline-offset:2px; }
  .door:hover { transform: translateY(-2px); box-shadow: 0 16px 46px rgba(0,0,0,.35); }
  .door .label { position:absolute; inset:12px auto auto 12px; background: rgba(0,0,0,.4); padding:6px 10px; border-radius: 999px; font-weight:600; font-size:14px }
  .num {
    position:absolute; right:12px; top:10px; font-size: 28px; font-weight: 800;
    background: linear-gradient(180deg, #fff, #f3e6b0); color:#1a1f2b; padding:6px 12px; border-radius: 10px;
    box-shadow: var(--glow);
  }
  .pane {
    position:absolute; inset:0; display:grid; place-items:center; background:
      linear-gradient(135deg, rgba(255,255,255,.08), rgba(255,255,255,.0) 40%),
      radial-gradient(220px 140px at -10% 110%, rgba(255,215,130,.08), transparent 60%),
      linear-gradient(0deg, rgba(255,255,255,.04), rgba(255,255,255,.06));
  }
  .pane svg { width:64px; height:64px; opacity:.85; filter: drop-shadow(0 6px 12px rgba(0,0,0,.35)); }
  .locked::after {
    content:"Locked until its day"; position:absolute; left:12px; bottom:12px; font-size:12px; opacity:.75;
  }
  .solved .pane { background: linear-gradient(0deg, rgba(60,255,185,.08), rgba(120,255,210,.08)); }
  .solved .label::after{ content:" ✓"; color:#9cffd7 }

  /* Modal */
  dialog { width:min(720px, 92%); border:none; border-radius:20px; padding:0; overflow:hidden; background:#0f1b33; color:#eef2ff; }
  dialog::backdrop { background: rgba(0,0,0,.6); backdrop-filter: blur(2px); }
  .modal-head { display:flex; align-items:center; gap:14px; padding:18px 22px; background: linear-gradient(180deg, #112344, #0c1a33); border-bottom:1px solid rgba(255,255,255,.08)}
  .modal-head h3 { margin:0; font-size:20px; }
  .pill { margin-left:auto; font-size:12px; padding:6px 10px; border:1px solid rgba(255,255,255,.12); border-radius:999px; opacity:.8 }
  .modal-body { padding: 18px 22px 22px; background: linear-gradient(0deg, rgba(255,255,255,.03), rgba(255,255,255,.06)); }
  .modal-actions { display:flex; gap:10px; padding: 0 22px 22px; }
  .btn {
    appearance:none; border:none; cursor:pointer; font-weight:700; padding:12px 16px; border-radius:12px;
    background: linear-gradient(180deg, var(--gold), var(--gold-soft)); color:#1a1f2b; box-shadow: var(--glow);
  }
  .btn.secondary{ background:rgba(255,255,255,.1); color:#fff; box-shadow:none; border:1px solid rgba(255,255,255,.1) }
  .input { width:100%; padding:12px 14px; border-radius:12px; border:1px solid rgba(255,255,255,.14); background:#0a1326; color:#e6eeff }
  .correct { color:#9cffd7; font-weight:700 }
  .wrong { color:#ffb3b3; font-weight:700 }
  .note { font-size: 12px; opacity:.75 }

  footer { text-align:center; margin: 40px 0 0; opacity:.75 }
  a { color: var(--gold-soft) }
</style>
</head>
<body>
<div class="sky" aria-hidden="true" id="sky"></div>
<div class="container">
  <header>
    <h1 class="title">The Puzzles Club • Magical Window Calendar</h1>
    <p class="subtitle">Tap a window to reveal today's mini‑challenge. Solve it to light the window! ✨</p>
  </header>

  <div class="ribbon" id="ribbon">
    <strong>Demo mode:</strong> All 3 windows are openable so you can preview the flow. When you embed on your site, set <code>data-demo="false"</code> to gate by date (America/Phoenix).
  </div>

  <main class="grid" id="grid" data-demo="true" aria-label="Calendar windows">
    <!-- Doors will be injected by JS -->
  </main>

  <footer>
    © <span id="year"></span> The Puzzles Club · <span class="note">Self‑contained, no external files</span>
  </footer>
</div>

<!-- Modal Template -->
<dialog id="modal" aria-labelledby="modalTitle">
  <div class="modal-head">
    <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M12 2l2.09 6.26H20.5l-5.17 3.76 1.97 6.08L12 16.26 6.7 18.1l1.97-6.08L3.5 8.26h6.41L12 2z" stroke="#e6c766" stroke-width="1.2"/></svg>
    <h3 id="modalTitle">Day</h3>
    <span class="pill" id="pill"></span>
  </div>
  <div class="modal-body" id="modalBody"></div>
  <div class="modal-actions">
    <button class="btn secondary" id="closeBtn" value="cancel">Close</button>
    <button class="btn" id="solveBtn">Check Answer</button>
  </div>
</dialog>

<script>
(function(){
  const TZ = 'America/Phoenix';
  const grid = document.getElementById('grid');
  const modal = document.getElementById('modal');
  const modalTitle = document.getElementById('modalTitle');
  const modalBody = document.getElementById('modalBody');
  const pill = document.getElementById('pill');
  const closeBtn = document.getElementById('closeBtn');
  const solveBtn = document.getElementById('solveBtn');
  const yearEl = document.getElementById('year');
  yearEl.textContent = new Date().getFullYear();

  // Twinkle stars (pure cosmetic)
  const sky = document.getElementById('sky');
  for (let i=0;i<80;i++){
    const s=document.createElement('div'); s.className='twinkle';
    s.style.left = Math.random()*100 + 'vw';
    s.style.top = Math.random()*100 + 'vh';
    s.style.opacity = (Math.random()*0.8+0.2).toFixed(2);
    sky.appendChild(s);
  }

  const demoMode = grid.getAttribute('data-demo') === 'true';

  // Define 3 days of content (you can extend to 24)
  const DAYS = [
    { day: 1, label: 'Word Ladder', icon: ladderIcon(), content: wordLadder(), answer: ['LIGHT'], hint: 'From "L" to a 5‑letter word meaning illumination.' },
    { day: 2, label: 'Riddle', icon: riddleIcon(), content: riddle(), answer: ['SHADOW'], hint: 'It follows you but never leads.' },
    { day: 3, label: 'Cipher', icon: cipherIcon(), content: caesar(), answer: ['PUZZLE'], hint: 'Shift letters by +3.' }
  ];

  // Build doors
  DAYS.forEach(({day, label, icon}) => {
    const door=document.createElement('button');
    door.className='door'; door.setAttribute('aria-haspopup','dialog'); door.setAttribute('data-day', day);

    const pane=document.createElement('div'); pane.className='pane'; pane.innerHTML = icon;
    const tag=document.createElement('span'); tag.className='label'; tag.textContent = label;
    const num=document.createElement('span'); num.className='num'; num.textContent = day;

    door.appendChild(pane); door.appendChild(tag); door.appendChild(num);

    // lock logic by date
    const now = new Date();
    const today = new Date( new Date(now).toLocaleString('en-US', { timeZone: TZ }) );
    const currentDay = demoMode ? 31 : today.getDate();
    const unlocked = day <= currentDay; // gate by day-of-month in non-demo
    if(!unlocked){ door.classList.add('locked'); door.disabled = true; }

    // solved state from localStorage
    const key = `puzzlesclub_demo_solved_${day}`;
    if(localStorage.getItem(key)==='1'){ door.classList.add('solved'); }

    door.addEventListener('click', ()=> openDay(day));
    grid.appendChild(door);
  });

  function openDay(day){
    const D = DAYS.find(d=>d.day===day);
    modalTitle.textContent = `Day ${day} • ${D.label}`;
    pill.textContent = `Hint: ${D.hint}`;
    modalBody.innerHTML = '';
    modalBody.appendChild(D.content.root);
    solveBtn.onclick = () => {
      const guess = D.content.getAnswer().trim().toUpperCase();
      const ok = D.answer.includes(guess);
      D.content.setResult(ok);
      if(ok){
        markSolved(day);
      }
    };
    modal.showModal();
  }

  function markSolved(day){
    localStorage.setItem(`puzzlesclub_demo_solved_${day}`,'1');
    const btn = grid.querySelector(`[data-day="${day}"]`);
    if(btn) btn.classList.add('solved');
  }

  closeBtn.addEventListener('click', ()=> modal.close());

  // --- Puzzle builders ---
  function wordLadder(){
    const root = el('div');
    root.innerHTML = `
      <p><strong>Build to the final word:</strong> Start with <em>L</em>. Each step adds one letter and forms a real English word, ending at 5 letters.</p>
      <ol>
        <li>2 letters: <input class="input" id="w2" placeholder="e.g., la"/></li>
        <li>3 letters: <input class="input" id="w3"/></li>
        <li>4 letters: <input class="input" id="w4"/></li>
        <li>5 letters: <input class="input" id="w5"/></li>
      </ol>
      <p class="note">All words must chain so that each new word begins with the last letter of the previous word.</p>
      <p id="wlResult"></p>
    `;
    const res = root.querySelector('#wlResult');
    function getAnswer(){
      return root.querySelector('#w5').value || '';
    }
    function setResult(ok){ res.innerHTML = ok? '<span class="correct">Correct! Final word LIGHT.</span>' : '<span class="wrong">Not quite. Check the chain and try again.</span>'; }
    return { root, getAnswer, setResult };
  }

  function riddle(){
    const root = el('div');
    root.innerHTML = `
      <p><strong>Riddle:</strong> I am born in light, yet I grow in shade. I follow you all day but vanish when you fade. What am I?</p>
      <input class="input" id="rid" placeholder="Type your answer"/>
      <p id="ridResult"></p>
    `;
    const res = root.querySelector('#ridResult');
    function getAnswer(){ return root.querySelector('#rid').value || ''; }
    function setResult(ok){ res.innerHTML = ok? '<span class="correct">Correct! SHADOW.</span>' : '<span class="wrong">Close! Think about sunlight.</span>'; }
    return { root, getAnswer, setResult };
  }

  function caesar(){
    const root = el('div');
    const cipher = caesarShift('MVWWIB', -3); // PUZZLE -> shift -3 to display
    root.innerHTML = `
      <p><strong>Caesar Cipher (+3):</strong> Decode this word then enter it below.</p>
      <pre style="font-size:28px; letter-spacing:4px; background:rgba(255,255,255,.06); padding:12px 14px; border-radius:12px;">${cipher}</pre>
      <input class="input" id="ciph" placeholder="Decoded word"/>
      <p id="ciphResult"></p>
    `;
    const res = root.querySelector('#ciphResult');
    function getAnswer(){ return root.querySelector('#ciph').value || ''; }
    function setResult(ok){ res.innerHTML = ok? '<span class="correct">Correct! PUZZLE.</span>' : '<span class="wrong">Not quite. Remember: shift letters forward by 3.</span>'; }
    return { root, getAnswer, setResult };
  }

  function caesarShift(str, n){
    const A='A'.charCodeAt(0), Z='Z'.charCodeAt(0);
    return str.toUpperCase().split('').map(ch=>{
      const c=ch.charCodeAt(0); if(c<A||c>Z) return ch;
      let x=((c-A+n)%26+26)%26 + A; return String.fromCharCode(x);
    }).join('');
  }

  function el(tag, props){ const n=document.createElement(tag); if(props) Object.assign(n, props); return n; }

  // Simple inline icons (SVG)
  function ladderIcon(){
    return `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
      <rect x="6" y="3" width="2" height="18" rx="1" fill="#e6c766"/>
      <rect x="16" y="3" width="2" height="18" rx="1" fill="#e6c766"/>
      <rect x="7" y="6" width="10" height="2" rx="1" fill="#f3e6b0"/>
      <rect x="7" y="10" width="10" height="2" rx="1" fill="#f3e6b0"/>
      <rect x="7" y="14" width="10" height="2" rx="1" fill="#f3e6b0"/>
    </svg>`;
  }
  function riddleIcon(){
    return `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
      <path d="M12 3a7 7 0 017 7c0 2.5-1.32 4.33-3.2 5.6-.96.66-1.8 1.28-1.8 2.4v.5h-2v-.6c0-2.1 1.34-3 2.6-3.86C16.6 13.2 17 12.25 17 10a5 5 0 10-10 0H5a7 7 0 017-7z" stroke="#e6c766" stroke-width="1.2"/>
      <circle cx="12" cy="20" r="1.6" fill="#f3e6b0"/>
    </svg>`;
  }
  function cipherIcon(){
    return `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
      <circle cx="12" cy="12" r="8" stroke="#e6c766" stroke-width="1.2"/>
      <path d="M12 4v8l6 6" stroke="#f3e6b0" stroke-width="1.2"/>
    </svg>`;
  }
})();
</script>
</body>
</html>

 

SOON

Who We Are

This is your About section. This space is a great opportunity to give a full background on who you are, what you do and what your site has to offer. Your users are genuinely interested in learning more about you, so don’t be afraid to share personal anecdotes to create a more friendly quality.
 

Double click on the text box to start editing your content and make sure to add all the relevant details you want site visitors to know. If you’re a business, talk about how you started and share your professional journey. Explain your core values, your commitment to customers and how you stand out from the crowd. Add a photo, gallery or video for even more engagement.

Get on the List

Sign up to receive the first word when we go live.

Thanks for submitting!

  • Facebook
  • Twitter
  • Instagram
  • LinkedIn
bottom of page