{"id":8309,"date":"2025-08-14T16:48:19","date_gmt":"2025-08-14T11:18:19","guid":{"rendered":"https:\/\/rbplanner.in\/?page_id=8309"},"modified":"2025-08-14T16:58:22","modified_gmt":"2025-08-14T11:28:22","slug":"pomodoro-timer","status":"publish","type":"page","link":"https:\/\/rbplanner.in\/index.php\/pomodoro-timer\/","title":{"rendered":"Pomodoro Timer"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"8309\" class=\"elementor elementor-8309\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3c36a22 e-flex e-con-boxed e-con e-parent\" data-id=\"3c36a22\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-51749ff elementor-widget elementor-widget-heading\" data-id=\"51749ff\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Pomodoro Timer<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d4ed578 elementor-widget elementor-widget-html\" data-id=\"d4ed578\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- RB Pomodoro v5 \u2014 clean gradient UI + Weekly\/Monthly CSV reports -->\r\n<div id=\"rbp5\">\r\n  <style>\r\n    \/* ===== Scope & Theme (light, like your screenshot) ===== *\/\r\n    #rbp5{--font: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, Arial;\r\n          --blueA:#3b82f6; --blueB:#2563eb;          \/* header + primary buttons *\/\r\n          --numA:#7c3aed; --numB:#8b5cf6;            \/* big number gradient *\/\r\n          --bg:#ffffff; --card:#ffffff; --text:#0f172a; --muted:#64748b;\r\n          --line:#e2e8f0; --shadow:0 20px 40px rgba(2,6,23,.08);\r\n          --radius:22px; --radius-lg:26px}\r\n    #rbp5,[id=\"rbp5\"] *{box-sizing:border-box;font-family:var(--font)}\r\n    #rbp5 .wrap{max-width:1100px;margin:24px auto;padding:0 12px}\r\n    #rbp5 .grid{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(310px,1fr))}\r\n    #rbp5 .card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:var(--shadow);overflow:hidden}\r\n\r\n    \/* Header (force white text\/icons) *\/\r\n    #rbp5 .head{background:linear-gradient(135deg,var(--blueA),var(--blueB));padding:18px 20px;\r\n                display:flex;align-items:center;gap:10px;color:#fff !important}\r\n    #rbp5 .head h3{margin:0;font-size:18px;font-weight:800;letter-spacing:.2px;color:#fff !important}\r\n    #rbp5 .head .icon{width:28px;height:28px;border-radius:10px;background:rgba(255,255,255,.18);display:grid;place-items:center}\r\n\r\n    #rbp5 .body{padding:18px}\r\n    #rbp5 label{display:block;font-size:12px;color:var(--muted);font-weight:800;letter-spacing:.04em;text-transform:uppercase;margin:10px 4px}\r\n    #rbp5 input[type=\"text\"],#rbp5 input[type=\"number\"]{\r\n      width:100%;border:1px solid var(--line);background:#f8fafc;border-radius:999px;padding:12px 16px;outline:0;\r\n      font-weight:600;color:var(--text)\r\n    }\r\n    #rbp5 input::placeholder{color:#9aa5b1}\r\n\r\n    \/* Result box (like the percentage card) *\/\r\n    #rbp5 .result{border:1px solid var(--line);border-radius:18px;background:#f8fafc;padding:14px 16px;margin-top:12px}\r\n    #rbp5 .result .cap{display:flex;align-items:center;gap:8px;color:var(--muted);font-weight:700}\r\n    #rbp5 .result .big{margin-top:8px;font-weight:900;line-height:1;\r\n      font-size:clamp(40px,10vw,56px);\r\n      background:linear-gradient(135deg,var(--numA),var(--numB));\r\n      -webkit-background-clip:text;background-clip:text;color:transparent}\r\n    #rbp5 .result .sub{margin-top:6px;color:var(--muted);font-size:13px}\r\n\r\n    \/* Buttons *\/\r\n    #rbp5 .btn{display:inline-flex;align-items:center;gap:10px;border:1px solid var(--line);padding:12px 16px;border-radius:14px;\r\n               background:#fff;color:var(--text);font-weight:800;cursor:pointer;transition:transform .06s ease, box-shadow .2s ease}\r\n    #rbp5 .btn:active{transform:translateY(1px)}\r\n    #rbp5 .btn[disabled]{opacity:.6;cursor:not-allowed}\r\n    #rbp5 .btn-primary{border-color:transparent;background:linear-gradient(135deg,var(--blueA),var(--blueB));color:#fff}\r\n    #rbp5 .btn-block{width:100%;justify-content:center}\r\n    #rbp5 .btnbar{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px}\r\n    #rbp5 .btnbar .btn{justify-content:center}\r\n\r\n    #rbp5 .tip{margin-top:8px;color:var(--muted);font-size:12px;text-align:right}\r\n    #rbp5 .row2{display:grid;grid-template-columns:1fr 1fr;gap:10px}\r\n\r\n    \/* Small icons *\/\r\n    #rbp5 svg{display:block}\r\n  <\/style>\r\n\r\n  <div class=\"wrap\">\r\n    <div class=\"grid\">\r\n      <!-- ========== LEFT: Pomodoro Timer ========== -->\r\n      <section class=\"card\" id=\"timer-card\">\r\n        <div class=\"head\">\r\n          <div class=\"icon\" aria-hidden=\"true\">\r\n            <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n              <circle cx=\"12\" cy=\"12\" r=\"8\" stroke=\"white\" stroke-width=\"2\"\/>\r\n              <path d=\"M12 8v5l3 2\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/>\r\n            <\/svg>\r\n          <\/div>\r\n          <h3>Pomodoro Timer<\/h3>\r\n        <\/div>\r\n        <div class=\"body\">\r\n          <label for=\"task\">Task Name<\/label>\r\n          <input id=\"task\" type=\"text\" placeholder=\"e.g., Biology \u2013 Cell Cycle\" \/>\r\n\r\n          <div class=\"result\" aria-live=\"polite\">\r\n            <div class=\"cap\">\r\n              <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M3 13a9 9 0 1 0 6-8.66\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\/><\/svg>\r\n              <span>Your Session<\/span>\r\n            <\/div>\r\n            <div class=\"big\" id=\"time\">25:00<\/div>\r\n            <div class=\"sub\" id=\"meta\">Work \u2022 Pomodoro 1 of 4<\/div>\r\n          <\/div>\r\n\r\n          <div class=\"btnbar\">\r\n            <button class=\"btn btn-primary\" id=\"start\">\r\n              <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\"><path d=\"M8 5v14l11-7z\" fill=\"currentColor\"\/><\/svg>\r\n              Start\r\n            <\/button>\r\n            <button class=\"btn\" id=\"pause\" disabled>\r\n              <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\"><path d=\"M6 5h4v14H6zM14 5h4v14h-4z\" fill=\"currentColor\"\/><\/svg>\r\n              Pause\r\n            <\/button>\r\n            <button class=\"btn\" id=\"resume\" disabled>\r\n              <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\"><path d=\"M8 5v14l11-7z\" fill=\"currentColor\"\/><\/svg>\r\n              Resume\r\n            <\/button>\r\n            <button class=\"btn\" id=\"skip\" disabled>\r\n              <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\"><path d=\"M5 5l8 7-8 7V5zm10 0h2v14h-2V5z\" fill=\"currentColor\"\/><\/svg>\r\n              Skip\r\n            <\/button>\r\n          <\/div>\r\n\r\n          <button class=\"btn btn-primary btn-block\" id=\"reset\" style=\"margin-top:10px\">\r\n            <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\"><path d=\"M12 6V3L8 7l4 4V8a6 6 0 1 1-6 6H4a8 8 0 1 0 8-8z\" fill=\"currentColor\"\/><\/svg>\r\n            Reset\r\n          <\/button>\r\n\r\n          <div class=\"tip\" id=\"status\"><\/div>\r\n        <\/div>\r\n      <\/section>\r\n\r\n      <!-- ========== RIGHT: Settings & Reports ========== -->\r\n      <section class=\"card\" id=\"settings-card\">\r\n        <div class=\"head\">\r\n          <div class=\"icon\" aria-hidden=\"true\">\r\n            <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n              <path d=\"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Z\" stroke=\"white\" stroke-width=\"2\"\/>\r\n              <path d=\"M19.5 12c0-.34.03-.68.08-1.01l1.96-1.54-1.9-3.29-2.33.94a7.9 7.9 0 0 0-1.75-1.01l-.35-2.46H9.85l-.35 2.46c-.62.25-1.21.58-1.75 1.01l-2.33-.94-1.9 3.29L5.48 11c-.05.33-.08.67-.08 1s.03.67.08 1l-1.96 1.54 1.9 3.29 2.33-.94c.54.43 1.13.77 1.75 1.01l.35 2.46h4.26l.35-2.46c.62-.24 1.21-.58 1.75-1.01l2.33.94 1.9-3.29-1.96-1.54c.05-.33.08-.67.08-1Z\" stroke=\"white\" stroke-width=\"2\"\/>\r\n            <\/svg>\r\n          <\/div>\r\n          <h3>Session Settings<\/h3>\r\n        <\/div>\r\n        <div class=\"body\">\r\n          <label for=\"count\">Number of Pomodoros<\/label>\r\n          <input id=\"count\" type=\"number\" min=\"1\" value=\"4\" \/>\r\n\r\n          <div class=\"row2\">\r\n            <div>\r\n              <label for=\"work\">Work (minutes)<\/label>\r\n              <input id=\"work\" type=\"number\" min=\"1\" value=\"25\" \/>\r\n            <\/div>\r\n            <div>\r\n              <label for=\"short\">Short Break<\/label>\r\n              <input id=\"short\" type=\"number\" min=\"1\" value=\"5\" \/>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <div class=\"row2\">\r\n            <div>\r\n              <label for=\"long\">Long Break<\/label>\r\n              <input id=\"long\" type=\"number\" min=\"1\" value=\"15\" \/>\r\n            <\/div>\r\n            <div>\r\n              <label for=\"after\">Long Break After (N)<\/label>\r\n              <input id=\"after\" type=\"number\" min=\"1\" value=\"4\" \/>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <div class=\"row2\" style=\"margin-top:10px\">\r\n            <button class=\"btn\" id=\"toggleAuto\">Auto-start: <span id=\"autoFlag\">On<\/span><\/button>\r\n            <button class=\"btn\" id=\"toggleSound\">Sound: <span id=\"soundFlag\">On<\/span><\/button>\r\n          <\/div>\r\n\r\n          <button class=\"btn btn-primary btn-block\" id=\"save\" style=\"margin-top:12px\">\r\n            <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\"><path d=\"M5 13l4 4L19 7\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg>\r\n            Save Settings\r\n          <\/button>\r\n\r\n          <!-- Reports -->\r\n          <div class=\"result\" style=\"margin-top:14px\">\r\n            <div class=\"cap\">\r\n              <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M3 12h18M3 7h18M3 17h18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\/><\/svg>\r\n              <span>Reports (CSV)<\/span>\r\n            <\/div>\r\n            <div class=\"row2\" style=\"margin-top:10px\">\r\n              <button class=\"btn btn-primary\" id=\"dlWeek\">Download Weekly<\/button>\r\n              <button class=\"btn btn-primary\" id=\"dlMonth\">Download Monthly<\/button>\r\n            <\/div>\r\n            <div class=\"sub\" id=\"reportHint\" style=\"margin-top:8px\">\r\n              Reports include each completed WORK session with date, task, and minutes.\r\n            <\/div>\r\n          <\/div>\r\n        <\/div>\r\n      <\/section>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <script>\r\n    (function(){\r\n      const $=s=>document.querySelector(s), $$=s=>document.querySelectorAll(s);\r\n      const ui = {\r\n        task:  $('#task'),\r\n        time:  $('#time'),\r\n        meta:  $('#meta'),\r\n        start: $('#start'),\r\n        pause: $('#pause'),\r\n        resume:$('#resume'),\r\n        skip:  $('#skip'),\r\n        reset: $('#reset'),\r\n        status:$('#status'),\r\n        inputs:{\r\n          count: $('#count'),\r\n          work:  $('#work'),\r\n          short: $('#short'),\r\n          long:  $('#long'),\r\n          after: $('#after')\r\n        },\r\n        save: $('#save'),\r\n        autoBtn: $('#toggleAuto'),\r\n        autoFlag: $('#autoFlag'),\r\n        soundBtn: $('#toggleSound'),\r\n        soundFlag: $('#soundFlag'),\r\n        dlWeek: $('#dlWeek'),\r\n        dlMonth: $('#dlMonth'),\r\n        reportHint: $('#reportHint')\r\n      };\r\n\r\n      \/* ========= State ========= *\/\r\n      const S = {\r\n        mode:'work', count:4, current:1,\r\n        work:25, short:5, long:15, after:4,\r\n        totalMs:25*60*1000, leftMs:25*60*1000,\r\n        running:false, endAt:0, raf:0,\r\n        auto:true, sound:true, lastSecond:-1\r\n      };\r\n      const LS_SETTINGS='rbpomo_v5';\r\n      const LS_LOGS='rbpomo_v5_logs';\r\n\r\n      \/* ========= Utils ========= *\/\r\n      const pad=n=>String(n).padStart(2,'0');\r\n      const clamp=(n,min,max)=>Math.max(min,Math.min(max,Number(n)||min));\r\n      function fmt(ms){\r\n        const sec = Math.max(0, Math.ceil(ms\/1000));\r\n        return `${pad(Math.floor(sec\/60))}:${pad(sec%60)}`;\r\n      }\r\n      function setMeta(){\r\n        const label = S.mode==='work' ? `Work \u2022 Pomodoro ${S.current} of ${S.count}`\r\n                    : S.mode==='short' ? 'Short Break' : 'Long Break';\r\n        const task = ui.task.value.trim();\r\n        ui.meta.textContent = task ? `${label} \u2022 ${task}` : label;\r\n      }\r\n      function setPhase(mode){\r\n        S.mode = mode;\r\n        const m = (mode==='work'?S.work:(mode==='short'?S.short:S.long));\r\n        S.totalMs = m*60*1000;\r\n        S.leftMs  = S.totalMs;\r\n        S.lastSecond = -1; \/\/ force repaint\r\n        ui.time.textContent = fmt(S.leftMs);\r\n        setMeta();\r\n      }\r\n      function toggleControls(done=false){\r\n        ui.start.disabled  = S.running || S.leftMs<=0 || done;\r\n        ui.pause.disabled  = !S.running || done;\r\n        ui.resume.disabled = S.running || S.leftMs<=0 || done;\r\n        ui.skip.disabled   = S.leftMs<=0 || done;\r\n      }\r\n      function flash(msg){\r\n        ui.status.textContent = msg;\r\n        ui.status.style.opacity='1';\r\n        setTimeout(()=>ui.status.style.opacity='0', 1100);\r\n      }\r\n\r\n      \/* ========= Persistence ========= *\/\r\n      function load(){\r\n        try{\r\n          const x = JSON.parse(localStorage.getItem(LS_SETTINGS))||{};\r\n          S.count = +x.count||4; S.work=+x.work||25; S.short=+x.short||5; S.long=+x.long||15; S.after=+x.after||4;\r\n          S.auto = x.auto!==undefined ? !!x.auto : true; S.sound = x.sound!==undefined ? !!x.sound : true;\r\n          if(x.task) ui.task.value = x.task;\r\n          ui.inputs.count.value=S.count; ui.inputs.work.value=S.work; ui.inputs.short.value=S.short;\r\n          ui.inputs.long.value=S.long; ui.inputs.after.value=S.after;\r\n          ui.autoFlag.textContent=S.auto?'On':'Off';\r\n          ui.soundFlag.textContent=S.sound?'On':'Off';\r\n          setPhase('work'); setMeta(); toggleControls();\r\n          \/\/ ensure logs array exists\r\n          const logs = JSON.parse(localStorage.getItem(LS_LOGS)||'[]');\r\n          localStorage.setItem(LS_LOGS, JSON.stringify(logs));\r\n          updateReportHint();\r\n        }catch(e){}\r\n      }\r\n      function save(show=true){\r\n        S.count = clamp(ui.inputs.count.value,1,999);\r\n        S.work  = clamp(ui.inputs.work.value,1,999);\r\n        S.short = clamp(ui.inputs.short.value,1,999);\r\n        S.long  = clamp(ui.inputs.long.value,1,999);\r\n        S.after = clamp(ui.inputs.after.value,1,999);\r\n        localStorage.setItem(LS_SETTINGS, JSON.stringify({\r\n          task: ui.task.value.trim(), count:S.count, work:S.work, short:S.short, long:S.long, after:S.after,\r\n          auto:S.auto, sound:S.sound\r\n        }));\r\n        if(show) flash('Saved');\r\n        if(!S.running){ S.current=1; setPhase('work'); }\r\n      }\r\n\r\n      \/* ========= Logger ========= *\/\r\n      function logWorkSession(){\r\n        const logs = JSON.parse(localStorage.getItem(LS_LOGS)||'[]');\r\n        logs.push({\r\n          ts: Date.now(),\r\n          task: ui.task.value.trim() || 'Unnamed task',\r\n          minutes: S.totalMs\/60000  \/\/ the scheduled work length\r\n        });\r\n        localStorage.setItem(LS_LOGS, JSON.stringify(logs));\r\n        updateReportHint();\r\n      }\r\n      function updateReportHint(){\r\n        const logs = JSON.parse(localStorage.getItem(LS_LOGS)||'[]');\r\n        if(!logs.length){\r\n          ui.reportHint.textContent = 'No completed work sessions yet. Start the timer to log sessions.';\r\n          return;\r\n        }\r\n        const totalMin = logs.reduce((a,b)=>a + (b.minutes||0), 0);\r\n        ui.reportHint.textContent = `Saved ${logs.length} sessions \u2022 ${Math.round(totalMin)} total focus minutes.`;\r\n      }\r\n\r\n      \/* ========= Timer Engine (RAF, wall-clock; updates text once\/sec) ========= *\/\r\n      function start(){\r\n        if(S.running) return;\r\n        S.running=true;\r\n        S.endAt = performance.now()+S.leftMs;\r\n        loop();\r\n        toggleControls();\r\n      }\r\n      function loop(){\r\n        if(!S.running) return;\r\n        const now=performance.now();\r\n        S.leftMs=Math.max(0,S.endAt-now);\r\n        const sec = Math.ceil(S.leftMs\/1000);\r\n        if(sec!==S.lastSecond){\r\n          S.lastSecond=sec;\r\n          ui.time.textContent = fmt(S.leftMs);\r\n        }\r\n        if(S.leftMs<=0){\r\n          S.running=false;\r\n          complete(false);\r\n          return;\r\n        }\r\n        S.raf=requestAnimationFrame(loop);\r\n      }\r\n      function pause(){\r\n        if(!S.running) return;\r\n        S.running=false;\r\n        cancelAnimationFrame(S.raf);\r\n        toggleControls();\r\n      }\r\n      function resume(){ if(!S.running && S.leftMs>0) start(); }\r\n      function reset(){\r\n        cancelAnimationFrame(S.raf);\r\n        S.running=false; S.current=1; setPhase('work'); toggleControls();\r\n      }\r\n      function skip(){ complete(true); }\r\n\r\n      function beep(times=1){\r\n        if(!S.sound) return;\r\n        try{\r\n          const C = new (window.AudioContext||window.webkitAudioContext)();\r\n          let d=0; for(let i=0;i<times;i++){\r\n            const o=C.createOscillator(), g=C.createGain(); o.type='sine'; o.frequency.value=900;\r\n            g.gain.setValueAtTime(0.0001,C.currentTime+d);\r\n            g.gain.exponentialRampToValueAtTime(0.25,C.currentTime+d+.02);\r\n            g.gain.exponentialRampToValueAtTime(0.0001,C.currentTime+d+.35);\r\n            o.connect(g); g.connect(C.destination); o.start(C.currentTime+d); o.stop(C.currentTime+d+.4); d+=.5;\r\n          }\r\n          setTimeout(()=>C.close(), 1200);\r\n        }catch(e){}\r\n      }\r\n\r\n      function complete(skipped){\r\n        if(!skipped) beep();\r\n        if(S.mode==='work'){\r\n          \/\/ log only if a WORK session finished naturally (not skipped)\r\n          if(!skipped) logWorkSession();\r\n          if(S.current % S.after===0){ setPhase('long'); } else { setPhase('short'); }\r\n        }else{\r\n          S.current++;\r\n          if(S.current>S.count){ finish(); return; }\r\n          setPhase('work');\r\n        }\r\n        toggleControls();\r\n        if(S.auto) start(); else pause();\r\n      }\r\n      function finish(){\r\n        ui.meta.textContent='All pomodoros done \ud83c\udf89';\r\n        ui.time.textContent='00:00';\r\n        beep(2);\r\n        toggleControls(true);\r\n      }\r\n\r\n      \/* ========= Reports (CSV) ========= *\/\r\n      function formatDate(ts){\r\n        const d=new Date(ts);\r\n        const yyyy=d.getFullYear(), mm=String(d.getMonth()+1).padStart(2,'0'), dd=String(d.getDate()).padStart(2,'0');\r\n        const hh=String(d.getHours()).padStart(2,'0'), mi=String(d.getMinutes()).padStart(2,'0');\r\n        return `${yyyy}-${mm}-${dd} ${hh}:${mi}`;\r\n      }\r\n      function buildCsv(days){\r\n        const logs = JSON.parse(localStorage.getItem(LS_LOGS)||'[]');\r\n        const cutoff = Date.now() - days*24*60*60*1000;\r\n        const rows = logs.filter(x=>x.ts>=cutoff).sort((a,b)=>a.ts-b.ts);\r\n        if(!rows.length) return null;\r\n\r\n        const total = rows.reduce((a,b)=>a+(b.minutes||0),0);\r\n        const header = ['DateTime','Task','Minutes'];\r\n        const body = rows.map(r=>[formatDate(r.ts), csvSafe(r.task), r.minutes]);\r\n        const footer = [['TOTAL','',''+Math.round(total)]];\r\n        const all = [header, ...body, [], ...footer];\r\n        let csv = '\\uFEFF'; \/\/ BOM for Excel\r\n        csv += all.map(line => line.map(csvSafe).join(',')).join('\\r\\n');\r\n        return csv;\r\n      }\r\n      function csvSafe(v){\r\n        if(v==null) return '';\r\n        const s=String(v);\r\n        return \/[\",\\r\\n]\/.test(s) ? `\"${s.replace(\/\"\/g,'\"\"')}\"` : s;\r\n      }\r\n      function download(csv, filename){\r\n        const blob = new Blob([csv], {type:'text\/csv;charset=utf-8;'});\r\n        const url = URL.createObjectURL(blob);\r\n        const a = document.createElement('a');\r\n        a.href=url; a.download=filename;\r\n        document.body.appendChild(a); a.click();\r\n        setTimeout(()=>{ URL.revokeObjectURL(url); a.remove(); }, 0);\r\n      }\r\n\r\n      ui.dlWeek.addEventListener('click', ()=>{\r\n        const csv = buildCsv(7);\r\n        if(!csv){ alert('No sessions in the last 7 days.'); return; }\r\n        download(csv, 'pomodoro_weekly_report.csv');\r\n      });\r\n      ui.dlMonth.addEventListener('click', ()=>{\r\n        const csv = buildCsv(30);\r\n        if(!csv){ alert('No sessions in the last 30 days.'); return; }\r\n        download(csv, 'pomodoro_monthly_report.csv');\r\n      });\r\n\r\n      \/* ========= Events ========= *\/\r\n      ui.start.addEventListener('click', start);\r\n      ui.pause.addEventListener('click', pause);\r\n      ui.resume.addEventListener('click', resume);\r\n      ui.reset.addEventListener('click', reset);\r\n      ui.skip.addEventListener('click', skip);\r\n\r\n      ui.save.addEventListener('click', ()=>save(true));\r\n      ui.task.addEventListener('input', ()=>save(false));\r\n\r\n      ui.autoBtn.addEventListener('click', ()=>{\r\n        S.auto=!S.auto; ui.autoFlag.textContent=S.auto?'On':'Off'; save(false);\r\n      });\r\n      ui.soundBtn.addEventListener('click', ()=>{\r\n        S.sound=!S.sound; ui.soundFlag.textContent=S.sound?'On':'Off'; save(false);\r\n      });\r\n\r\n      \/\/ Prevent accidental number change on scroll (mobile friendly)\r\n      $$('#rbp5 input[type=\"number\"]').forEach(inp=>{\r\n        inp.addEventListener('wheel', (e)=> e.target===document.activeElement?null:e.preventDefault(), {passive:false});\r\n      });\r\n\r\n      load();\r\n    })();\r\n  <\/script>\r\n<\/div>\r\n<!-- \/RB Pomodoro v5 -->\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-55f1c74 e-flex e-con-boxed e-con e-parent\" data-id=\"55f1c74\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-11c12c5 elementor-widget elementor-widget-text-editor\" data-id=\"11c12c5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h1>Pomodoro Timer \u2014 study in short, powerful bursts<\/h1><p data-start=\"234\" data-end=\"444\">If you struggle to sit down and <em data-start=\"266\" data-end=\"273\">start<\/em>, this timer will help.<br data-start=\"296\" data-end=\"299\" \/>Pick a task, press <strong data-start=\"318\" data-end=\"327\">Start<\/strong>, focus for one short block, then take a quick break. Repeat a few times and you\u2019ll be surprised how much you finish.<\/p><p data-start=\"446\" data-end=\"583\">Our timer is clean, mobile-friendly, and saves your finished work blocks so you can <strong data-start=\"530\" data-end=\"569\">download a weekly or monthly report<\/strong> in one click.<\/p><h2 data-start=\"585\" data-end=\"611\">What you can do with it<\/h2><ul data-start=\"612\" data-end=\"947\"><li data-start=\"612\" data-end=\"684\"><p data-start=\"614\" data-end=\"684\">Set your own times for <strong data-start=\"637\" data-end=\"645\">Work<\/strong>, <strong data-start=\"647\" data-end=\"662\">Short Break<\/strong>, and <strong data-start=\"668\" data-end=\"682\">Long Break<\/strong><\/p><\/li><li data-start=\"685\" data-end=\"739\"><p data-start=\"687\" data-end=\"739\">Choose how many <strong data-start=\"703\" data-end=\"716\">Pomodoros<\/strong> you want to complete<\/p><\/li><li data-start=\"740\" data-end=\"807\"><p data-start=\"742\" data-end=\"807\">Turn <strong data-start=\"747\" data-end=\"761\">Auto-start<\/strong> on to flow from work \u2192 break \u2192 next session<\/p><\/li><li data-start=\"808\" data-end=\"864\"><p data-start=\"810\" data-end=\"864\">Add a <strong data-start=\"816\" data-end=\"829\">Task Name<\/strong> so your reports make sense later<\/p><\/li><li data-start=\"865\" data-end=\"947\"><p data-start=\"867\" data-end=\"947\"><strong data-start=\"867\" data-end=\"891\">Download CSV reports<\/strong> for the last 7 or 30 days (open in Excel\/Google Sheets)<\/p><\/li><\/ul><h2 data-start=\"949\" data-end=\"981\">How to use (takes 10 seconds)<\/h2><ol data-start=\"982\" data-end=\"1317\"><li data-start=\"982\" data-end=\"1066\"><p data-start=\"985\" data-end=\"1066\">Type your task (e.g., <em data-start=\"1007\" data-end=\"1035\">Polity: Fundamental Rights<\/em> or <em data-start=\"1039\" data-end=\"1062\">Organic Chemistry\u2014GOC<\/em>).<\/p><\/li><li data-start=\"1067\" data-end=\"1121\"><p data-start=\"1070\" data-end=\"1121\">Set how many Pomodoros you want and your timings.<\/p><\/li><li data-start=\"1122\" data-end=\"1210\"><p data-start=\"1125\" data-end=\"1210\">Hit <strong data-start=\"1129\" data-end=\"1138\">Start<\/strong>. Use <strong data-start=\"1144\" data-end=\"1153\">Pause<\/strong>, <strong data-start=\"1155\" data-end=\"1165\">Resume<\/strong>, <strong data-start=\"1167\" data-end=\"1175\">Skip<\/strong>, or <strong data-start=\"1180\" data-end=\"1189\">Reset<\/strong> whenever you need.<\/p><\/li><li data-start=\"1211\" data-end=\"1317\"><p data-start=\"1214\" data-end=\"1317\">When you\u2019re done for the day, click <strong data-start=\"1250\" data-end=\"1269\">Download Weekly<\/strong> or <strong data-start=\"1273\" data-end=\"1293\">Download Monthly<\/strong> to save your study log.<\/p><\/li><\/ol><h2 data-start=\"1319\" data-end=\"1336\">Why this works<\/h2><ul data-start=\"1337\" data-end=\"1550\"><li data-start=\"1337\" data-end=\"1379\"><p data-start=\"1339\" data-end=\"1379\">Short deadlines make it easy to begin.<\/p><\/li><li data-start=\"1380\" data-end=\"1417\"><p data-start=\"1382\" data-end=\"1417\">Breaks stop you from burning out.<\/p><\/li><li data-start=\"1418\" data-end=\"1492\"><p data-start=\"1420\" data-end=\"1492\">Seeing your <strong data-start=\"1432\" data-end=\"1458\">weekly\/monthly minutes<\/strong> keeps you honest and motivated.<\/p><\/li><li data-start=\"1493\" data-end=\"1550\"><p data-start=\"1495\" data-end=\"1550\">Everything runs in your browser\u2014no signup, no tracking.<\/p><\/li><\/ul><h2 data-start=\"1552\" data-end=\"1567\">Who it\u2019s for<\/h2><p data-start=\"1568\" data-end=\"1692\">Students preparing for <strong data-start=\"1591\" data-end=\"1626\">UPSC, SSC, NEET, JEE, CLAT, CAT<\/strong>, college exams, or anyone who wants a focused study\/work routine.<\/p><h2 data-start=\"1694\" data-end=\"1707\">Quick tips<\/h2><ul data-start=\"1708\" data-end=\"1995\"><li data-start=\"1708\" data-end=\"1781\"><p data-start=\"1710\" data-end=\"1781\">Start with <strong data-start=\"1721\" data-end=\"1750\">25 min work + 5 min break<\/strong>. Increase later if you want.<\/p><\/li><li data-start=\"1782\" data-end=\"1846\"><p data-start=\"1784\" data-end=\"1846\">Keep one task per session. It\u2019s easier to report and review.<\/p><\/li><li data-start=\"1847\" data-end=\"1929\"><p data-start=\"1849\" data-end=\"1929\">If you keep getting distracted, shorten work time to 20 minutes and try again.<\/p><\/li><li data-start=\"1930\" data-end=\"1995\"><p data-start=\"1932\" data-end=\"1995\">Export the <strong data-start=\"1943\" data-end=\"1957\">weekly CSV<\/strong> every Sunday and note what went well.<\/p><\/li><\/ul><hr data-start=\"1997\" data-end=\"2000\" \/><h3 data-start=\"2002\" data-end=\"2010\">FAQs<\/h3><p data-start=\"2012\" data-end=\"2131\"><strong data-start=\"2012\" data-end=\"2035\">What is a Pomodoro?<\/strong><br data-start=\"2035\" data-end=\"2038\" \/>A short, focused work block followed by a short break. Do 3\u20134 rounds and take a longer break.<\/p><p data-start=\"2133\" data-end=\"2242\"><strong data-start=\"2133\" data-end=\"2162\">Can I change the timings?<\/strong><br data-start=\"2162\" data-end=\"2165\" \/>Yes\u2014every duration is customizable, including \u201cLong Break after N Pomodoros.\u201d<\/p><p data-start=\"2244\" data-end=\"2409\"><strong data-start=\"2244\" data-end=\"2272\">Where is my data stored?<\/strong><br data-start=\"2272\" data-end=\"2275\" \/>On your device (browser local storage). If you clear site data or switch devices, it won\u2019t carry over\u2014export CSV if you want a backup.<\/p><p data-start=\"2411\" data-end=\"2565\"><strong data-start=\"2411\" data-end=\"2443\">What do the reports include?<\/strong><br data-start=\"2443\" data-end=\"2446\" \/>Each completed <strong data-start=\"2461\" data-end=\"2469\">work<\/strong> session with date\/time, task name, and minutes. You can open the CSV in Excel or Google Sheets.<\/p><p data-start=\"2567\" data-end=\"2617\"><strong data-start=\"2567\" data-end=\"2582\">Is it free?<\/strong><br data-start=\"2582\" data-end=\"2585\" \/>Yes. Use it as much as you like.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Pomodoro Timer Pomodoro Timer Task Name Your Session 25:00 Work \u2022 Pomodoro 1 of 4 Start Pause Resume Skip Reset&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-8309","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/pages\/8309"}],"collection":[{"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/comments?post=8309"}],"version-history":[{"count":7,"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/pages\/8309\/revisions"}],"predecessor-version":[{"id":8319,"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/pages\/8309\/revisions\/8319"}],"wp:attachment":[{"href":"https:\/\/rbplanner.in\/index.php\/wp-json\/wp\/v2\/media?parent=8309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}