<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>5-Minute Timer</title>
<style>
  :root {
    --bg: #0d1117;
    --panel: #161b22;
    --text: #e6edf3;
    --muted: #8b949e;
    --border: #30363d;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; -webkit-user-select: none; user-select: none; }
  html, body { height: 100%; }
  body {
    background: radial-gradient(ellipse at center, #11161f 0%, var(--bg) 70%);
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    min-height: 100%; gap: 40px; padding: 24px;
  }

  .timer { position: relative; width: min(78vw, 420px); aspect-ratio: 1; display: grid; place-items: center; }
  .ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
  .ring .track { fill: none; stroke: var(--border); stroke-width: 8; }
  .ring .progress {
    fill: none; stroke-width: 12; stroke-linecap: round;
    transition: stroke 0.25s linear;
    filter: drop-shadow(0 0 10px currentColor);
  }

  .readout { display: flex; flex-direction: column; align-items: center; gap: 6px; }
  .time {
    font-variant-numeric: tabular-nums;
    font-family: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
    font-size: clamp(48px, 17vw, 96px); font-weight: 700; line-height: 1;
    letter-spacing: 1px; transition: color 0.25s linear;
  }
  .label { font-size: 13px; letter-spacing: 2px; text-transform: uppercase; color: var(--muted); }

  /* Flash the WHOLE background red when expired (past zero) */
  body.expired { animation: bgFlash 1s ease-in-out infinite; }   /* 1 Hz */
  @keyframes bgFlash {
    0%, 100% { background: var(--bg); }
    50%      { background: #c01f28; }
  }

  .controls { display: flex; gap: 14px; }
  button {
    font-family: inherit; font-size: 15px; font-weight: 600;
    color: var(--text); background: var(--panel);
    border: 1px solid var(--border); border-radius: 10px;
    padding: 12px 22px; min-width: 110px; cursor: pointer;
    transition: background 0.15s, border-color 0.15s, transform 0.05s;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  }
  button:hover { background: #1f2630; border-color: #484f58; }
  button:active { transform: translateY(1px); }
  button.primary { background: #1f6feb22; border-color: #1f6feb88; color: #cfe2ff; }
  button.primary:hover { background: #1f6feb33; }
  button svg { width: 16px; height: 16px; fill: currentColor; }

  .adjust { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; max-width: 430px; }
  .adj { min-width: 58px; padding: 9px 12px; font-size: 14px; }
  .adj[data-delta^="-"] { color: #ffc2c2; border-color: #5a2a2a; }
  .adj[data-delta^="-"]:hover { background: #261313; border-color: #7a3a3a; }
  .adj:not([data-delta^="-"]) { color: #bdf0cd; border-color: #2c5a3e; }
  .adj:not([data-delta^="-"]):hover { background: #16271c; border-color: #3c7a52; }
</style>
</head>
<body>
  <div class="timer" id="timer">
    <svg class="ring" viewBox="0 0 240 240">
      <circle class="track" cx="120" cy="120" r="110"></circle>
      <circle class="progress" id="progress" cx="120" cy="120" r="110"></circle>
    </svg>
    <div class="readout">
      <div class="time" id="time">5:00</div>
      <div class="label" id="label">ready</div>
    </div>
  </div>

  <div class="controls">
    <button class="primary" id="playBtn" aria-label="Play or pause">
      <svg id="playIcon" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
      <span id="playLabel">Start</span>
    </button>
    <button id="resetBtn" aria-label="Reset">
      <svg viewBox="0 0 24 24"><path d="M12 5V1L7 6l5 5V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7z"/></svg>
      <span>Reset</span>
    </button>
  </div>

  <div class="adjust" id="adjust">
    <button class="adj" data-delta="-60">&minus;60s</button>
    <button class="adj" data-delta="-30">&minus;30s</button>
    <button class="adj" data-delta="-10">&minus;10s</button>
    <button class="adj" data-delta="10">+10s</button>
    <button class="adj" data-delta="30">+30s</button>
    <button class="adj" data-delta="60">+60s</button>
  </div>

<script>
(function () {
  const TOTAL = 5 * 60;            // 5 minutes, seconds
  const R = 110;
  const CIRC = 2 * Math.PI * R;

  const $timer = document.getElementById('timer');
  const $time = document.getElementById('time');
  const $label = document.getElementById('label');
  const $progress = document.getElementById('progress');
  const $playBtn = document.getElementById('playBtn');
  const $playIcon = document.getElementById('playIcon');
  const $playLabel = document.getElementById('playLabel');
  const $resetBtn = document.getElementById('resetBtn');

  $progress.style.strokeDasharray = CIRC;

  const ICON_PLAY = 'M8 5v14l11-7z';
  const ICON_PAUSE = 'M6 5h4v14H6zM14 5h4v14h-4z';

  let remaining = TOTAL;   // seconds, may go negative
  let running = false;
  let endAt = 0;           // performance.now()/1000 + remaining, while running

  function now() { return performance.now() / 1000; }

  // green (120°) at full time -> red (0°) at zero
  function colorFor(r) {
    if (r > 0) {
      const hue = 120 * Math.max(0, Math.min(1, r / TOTAL));
      return `hsl(${hue.toFixed(1)}, 85%, 55%)`;
    }
    return 'hsl(0, 90%, 58%)';
  }

  function fmt(r) {
    let neg = false, secs;
    if (r > 0) { secs = Math.ceil(r - 1e-9); }
    else { secs = Math.ceil(-r - 1e-9); neg = secs > 0; }
    const m = Math.floor(secs / 60);
    const s = secs % 60;
    return (neg ? '-' : '') + m + ':' + String(s).padStart(2, '0');
  }

  function render() {
    const expired = remaining <= 0;
    const flashing = expired && running;   // only strobe while actually counting past 0
    const color = colorFor(remaining);

    $time.textContent = fmt(remaining);
    $time.style.color = flashing ? '#ffffff' : color;   // white over the strobe; red when paused-expired
    $progress.style.stroke = color;

    // ring: full at TOTAL, empty at <=0
    const frac = Math.max(0, Math.min(1, remaining / TOTAL));
    $progress.style.strokeDashoffset = CIRC * (1 - frac);

    $timer.classList.toggle('expired', expired);
    document.body.classList.toggle('expired', flashing);   // strobe stops when paused
    $label.textContent = expired ? 'time up' : (running ? 'running' : (remaining === TOTAL ? 'ready' : 'paused'));
  }

  function tick() {
    if (running) remaining = endAt - now();
    render();
    requestAnimationFrame(tick);
  }

  function setPlayingUI(isRunning) {
    $playIcon.querySelector('path').setAttribute('d', isRunning ? ICON_PAUSE : ICON_PLAY);
    $playLabel.textContent = isRunning ? 'Pause' : (remaining === TOTAL ? 'Start' : 'Resume');
  }

  function play() {
    if (running) return;
    endAt = now() + remaining;
    running = true;
    setPlayingUI(true);
  }
  function pause() {
    if (!running) return;
    remaining = endAt - now();
    running = false;
    setPlayingUI(false);
  }
  function toggle() { running ? pause() : play(); }
  function reset() {
    running = false;
    remaining = TOTAL;
    setPlayingUI(false);
    render();
  }
  function adjust(delta) {
    if (running) { endAt += delta; remaining = endAt - now(); }
    else { remaining += delta; }
    setPlayingUI(running);   // refresh Start/Resume label
    render();
  }

  $playBtn.addEventListener('click', toggle);
  $resetBtn.addEventListener('click', reset);
  document.querySelectorAll('.adj').forEach(b => {
    b.addEventListener('click', () => adjust(parseInt(b.dataset.delta, 10)));
  });
  document.addEventListener('keydown', (e) => {
    if (e.code === 'Space') { e.preventDefault(); toggle(); }
    else if (e.key === 'r' || e.key === 'R') { reset(); }
  });

  setPlayingUI(false);
  requestAnimationFrame(tick);
})();
</script>
</body>
</html>