/* Calendar and to-do widgets. Today is marked with aria-current="date"; event categories are a colour bar plus a word;
to-dos are real checkboxes with <label>s, and a short script keeps the "n of N done" count in step. */
.tw{--tw-ink:#0f172a;--tw-muted:#4b5768;--tw-line:#e2e8f0;--tw-accent:#1f5fae;--tw-box:#64748b;
background:#fff;color:var(--tw-ink);border:1px solid var(--tw-line);border-radius:16px;box-shadow:0 1px 2px rgba(15,23,42,.04),0 8px 24px rgba(15,23,42,.05);min-width:0}
.tw-head{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:16px 18px 12px}
.tw-title{font-size:1rem;font-weight:700}
.tw-sub{font-size:.78rem;color:var(--tw-muted)}
/* schedule */
.sc-week{list-style:none;display:grid;grid-template-columns:repeat(7,1fr);gap:4px;padding:0 14px 14px;border-bottom:1px solid var(--tw-line)}
.sc-week li{display:flex;flex-direction:column;align-items:center;gap:1px;padding:6px 0 4px;border-radius:10px;font-size:.7rem;color:var(--tw-muted)}
.sc-week b{font-size:.95rem;color:var(--tw-ink);font-variant-numeric:tabular-nums}
.sc-week i{font-style:normal;height:10px;line-height:10px;letter-spacing:1px;color:var(--tw-accent)}
.sc-week li[aria-current]{background:var(--tw-accent);color:#fff}
.sc-week li[aria-current] b,.sc-week li[aria-current] i{color:#fff}
.sc-list{list-style:none;padding:6px 18px 14px}
.sc-list li{display:grid;grid-template-columns:52px 1fr;gap:10px;padding:10px 0 10px 12px;border-left:3px solid var(--cat);margin:8px 0;background:#f8fafc;border-radius:0 10px 10px 0}
.sc-time{display:flex;flex-direction:column;font-size:.8rem;font-weight:600;font-variant-numeric:tabular-nums;color:var(--tw-ink)}
.sc-time time+span+time{font-weight:400;color:var(--tw-muted)}
.sc-ev{font-size:.88rem;font-weight:600}
.sc-meta{font-size:.76rem;color:var(--tw-muted)}
.sc-now{display:inline-block;margin-left:6px;padding:0 7px;border-radius:999px;background:#dcfce7;color:#166534;font-size:.7rem;font-weight:700;vertical-align:1px}
/* to-do */
.td-progress{display:flex;align-items:center;gap:10px;padding:0 18px 12px;font-size:.78rem;color:var(--tw-muted);font-variant-numeric:tabular-nums}
.td-progress progress{-webkit-appearance:none;appearance:none;flex:1;height:6px;border:0;border-radius:999px;background:var(--tw-line);overflow:hidden}
.td-progress progress::-webkit-progress-bar{background:var(--tw-line)}
.td-progress progress::-webkit-progress-value{background:#2a78d6;border-radius:999px}
.td-progress progress::-moz-progress-bar{background:#2a78d6;border-radius:999px}
.td-list{list-style:none;padding:0 18px 10px}
.td-list li{display:flex;align-items:flex-start;gap:12px;padding:11px 0;border-top:1px solid var(--tw-line)}
.td-list input{-webkit-appearance:none;appearance:none;flex:none;width:20px;height:20px;margin-top:1px;border:2px solid var(--tw-box);border-radius:6px;background:#fff;cursor:pointer;display:grid;place-items:center;transition:background .15s,border-color .15s}
.td-list input::after{content:"";width:9px;height:5px;border-left:2px solid #fff;border-bottom:2px solid #fff;transform:translateY(-1px) rotate(-45deg) scale(0);transition:transform .15s}
.td-list input:checked{background:var(--tw-accent);border-color:var(--tw-accent)}
.td-list input:checked::after{transform:translateY(-1px) rotate(-45deg) scale(1)}
.td-list input:focus-visible{outline:2px solid var(--tw-accent);outline-offset:2px}
.td-list label{font-size:.88rem;font-weight:600;cursor:pointer}
.td-list input:checked+div label{text-decoration:line-through;color:var(--tw-muted);font-weight:500}
.td-meta{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:.76rem;color:var(--tw-muted);margin-top:2px}
.td-pri{padding:0 7px;border-radius:5px;font-size:.7rem;font-weight:700}
.td-pri.is-high{color:#991b1b;background:#fee2e2}
.td-pri.is-med{color:#92400e;background:#fef3c7}
.td-pri.is-low{color:#334155;background:#e2e8f0}
/* deadlines */
.dl{padding:0 18px 12px}
.dl-group{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--tw-muted);padding:10px 0 4px}
.dl ul{list-style:none}
.dl li{display:flex;gap:10px;align-items:flex-start;padding:9px 0;border-top:1px solid var(--tw-line)}
.dl-av{flex:none;display:grid;place-items:center;width:28px;height:28px;border-radius:50%;color:#fff;font-size:.68rem;font-weight:700}
.dl-task{font-size:.86rem;font-weight:600}
.dl-meta{font-size:.76rem;color:var(--tw-muted)}
.dl-over,.dl-due{display:inline-flex;align-items:center;gap:4px;font-weight:600}
.dl-over{color:#b91c1c}
.dl-over svg,.dl-due svg{width:13px;height:13px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
@media (prefers-reduced-motion:reduce){.td-list input,.td-list input::after{transition:none}}
JavaScript
// Keeps the "n of N done" line and the bar in step with the checkboxes.
document.querySelectorAll('[data-todo]').forEach(box => {
const items = box.querySelectorAll('input[type="checkbox"]'), out = box.querySelector('[data-todo-count]'), bar = box.querySelector('[data-todo-bar]');
const update = () => {
const done = [...items].filter(i => i.checked).length;
if (out) out.textContent = `${done} of ${items.length} done`;
if (bar) { bar.max = items.length; bar.value = done; }
};
items.forEach(i => i.addEventListener('change', update));
update();
});
// Keeps the "n of N done" line and the bar in step with the checkboxes.
document.querySelectorAll('[data-todo]').forEach(box => {
const items = box.querySelectorAll('input[type="checkbox"]'), out = box.querySelector('[data-todo-count]'), bar = box.querySelector('[data-todo-bar]');
const update = () => {
const done = [...items].filter(i => i.checked).length;
if (out) out.textContent = `${done} of ${items.length} done`;
if (bar) bar.style.width = `${done / items.length * 100}%`;
};
items.forEach(i => i.addEventListener('change', update));
update();
});
// Keeps the "n of N done" line and the bar in step with the checkboxes.
document.querySelectorAll('[data-todo]').forEach(box => {
const items = box.querySelectorAll('input[type="checkbox"]'), out = box.querySelector('[data-todo-count]'), bar = box.querySelector('[data-todo-bar]');
const update = () => {
const done = [...items].filter(i => i.checked).length;
if (out) out.textContent = `${done} of ${items.length} done`;
if (bar) { bar.max = items.length; bar.value = done; }
};
items.forEach(i => i.addEventListener('change', update));
update();
});
Three widgets for planning a working day. The week strip with agenda shows Monday to Sunday with today highlighted and dots for how busy each day is, followed by today’s four meetings, each with a start and end time, a coloured bar, a category word and a Now badge on the one in progress. The to-do list has seven tasks as real checkboxes with labels, priority tags written as High, Medium and Low, a project and a due date; finished tasks are struck through, and a short script keeps the 3 of 7 done count and its bar in step. Upcoming deadlines groups six tasks under Overdue, Today and Monday, with assignee initials and an icon-and-word due line that turns red when a task is late. Use the agenda on a home dashboard, the to-do list in a side column and the deadlines list for team leads. Today is marked with aria-current=”date”, and the day dots have hidden text such as 4 events, so nothing depends on colour or dots alone.
What’s included
Week strip with today marked and per-day event dots
Agenda with times, category bars and a Now badge
To-do list built on real checkboxes and labels
Live done count and progress bar
Deadlines grouped by day with overdue warnings
Bootstrap version uses .form-check, .progress and .badge
Accessibility
Checkboxes have labels and are described by their priority, project and due date; their border meets 3:1 contrast and they show a focus outline. The done count is a polite live region. Today carries aria-current="date", day dots have hidden event counts, event times read as "09:30 to 10:00", and overdue items say so in words. Check transitions stop under prefers-reduced-motion.
Customise it
Set --tw-accent for today, checked boxes and dots, --tw-box for the checkbox border, and --cat on each agenda item for its category bar. In Bootstrap restyle .form-check-input inside .td-list; in Tailwind change the checked: and aria-[current]: classes.