diff --git a/css/focusMode.css b/css/focusMode.css
new file mode 100644
index 000000000..4307f99ed
--- /dev/null
+++ b/css/focusMode.css
@@ -0,0 +1,266 @@
+/* ─── Toolbar indicator pill ─────────────────────────────────────────────── */
+
+#focus-mode-indicator {
+ position: absolute;
+ /* centered horizontally over the tab bar area */
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 10;
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.82em;
+ font-weight: 700;
+ padding: 5px 16px;
+ border-radius: 20px;
+ white-space: nowrap;
+ background: #ffffff;
+ color: #111111;
+ border: none;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
+ cursor: pointer;
+ user-select: none;
+ pointer-events: auto;
+ letter-spacing: 0.01em;
+ transition: box-shadow 0.15s, background 0.15s;
+}
+
+#focus-mode-indicator:hover {
+ box-shadow: 0 3px 12px rgba(0, 0, 0, 0.3);
+ background: #f5f5f5;
+}
+
+#focus-mode-indicator.is-off-track {
+ background: #ffffff;
+ color: #c0392b;
+}
+
+.dark-theme #focus-mode-indicator {
+ background: #2a2a2a;
+ color: #ffffff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
+}
+
+.dark-theme #focus-mode-indicator:hover {
+ background: #383838;
+}
+
+.dark-theme #focus-mode-indicator.is-off-track {
+ color: #ff6b6b;
+}
+
+/* ─── Goal input modal ──────────────────────────────────────────────────── */
+
+#focus-mode-goal-modal {
+ max-width: 520px;
+}
+
+.focus-modal-hint {
+ font-size: 0.88em;
+ opacity: 0.65;
+ margin: -0.5em 0 1em 0;
+}
+
+.focus-goal-input {
+ display: block;
+ width: 100%;
+ box-sizing: border-box;
+ padding: 0.6em 0.8em;
+ font-size: 1em;
+ border: 1px solid rgba(0, 0, 0, 0.18);
+ border-radius: 6px;
+ background: transparent;
+ color: inherit;
+ outline: none;
+ margin-bottom: 1.2em;
+}
+
+.focus-goal-input:focus {
+ border-color: #007aff;
+ box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
+}
+
+.dark-mode .focus-goal-input {
+ border-color: rgba(255, 255, 255, 0.2);
+}
+
+.dark-mode .focus-goal-input:focus {
+ border-color: #0a84ff;
+ box-shadow: 0 0 0 2px rgba(10, 132, 255, 0.25);
+}
+
+.focus-modal-actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.focus-btn-primary {
+ background: #007aff;
+ color: #fff;
+ border: none;
+ border-radius: 6px;
+ padding: 0.5em 1.2em;
+ font-size: 0.95em;
+ font-weight: 600;
+ cursor: pointer;
+}
+
+.focus-btn-primary:hover {
+ background: #0066d6;
+}
+
+.dark-mode .focus-btn-primary {
+ background: #0a84ff;
+}
+
+.focus-btn-secondary {
+ background: transparent;
+ color: inherit;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 6px;
+ padding: 0.5em 1.1em;
+ font-size: 0.88em;
+ cursor: pointer;
+ opacity: 0.75;
+}
+
+.focus-btn-secondary:hover {
+ opacity: 1;
+ background: rgba(0, 0, 0, 0.06);
+}
+
+.dark-mode .focus-btn-secondary {
+ border-color: rgba(255, 255, 255, 0.2);
+}
+
+.dark-mode .focus-btn-secondary:hover {
+ background: rgba(255, 255, 255, 0.08);
+}
+
+/* ─── Drift alert bar ───────────────────────────────────────────────────── */
+
+#focus-mode-alert {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ z-index: 100;
+ display: flex;
+ align-items: center;
+ gap: 0.75em;
+ padding: 0.65em 1.1em;
+ background: #fff3cd;
+ border-top: 1px solid #f0c36d;
+ color: #5a4a00;
+ font-size: 0.88em;
+ animation: focus-alert-slide-in 0.25s ease-out;
+}
+
+@keyframes focus-alert-slide-in {
+ from { transform: translateY(100%); opacity: 0; }
+ to { transform: translateY(0); opacity: 1; }
+}
+
+.dark-mode #focus-mode-alert {
+ background: #3a2e00;
+ border-color: #6a5200;
+ color: #f0d080;
+}
+
+.focus-alert-icon {
+ font-size: 1.1em;
+ flex-shrink: 0;
+}
+
+#focus-mode-alert > span:nth-child(2) {
+ flex: 1;
+}
+
+.focus-alert-actions {
+ display: flex;
+ gap: 0.5em;
+ flex-shrink: 0;
+}
+
+.focus-alert-actions button {
+ padding: 0.3em 0.8em;
+ border-radius: 5px;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ background: rgba(0, 0, 0, 0.06);
+ color: inherit;
+ font-size: 0.9em;
+ cursor: pointer;
+ font-weight: 500;
+}
+
+.focus-alert-actions button:first-child {
+ background: #007aff;
+ color: #fff;
+ border-color: transparent;
+}
+
+.focus-alert-actions button:first-child:hover {
+ background: #0066d6;
+}
+
+.focus-alert-actions button:last-child:hover {
+ background: rgba(0, 0, 0, 0.12);
+}
+
+.dark-mode .focus-alert-actions button:first-child {
+ background: #0a84ff;
+}
+
+/* ─── Session summary modal ─────────────────────────────────────────────── */
+
+#focus-mode-summary {
+ max-width: 420px;
+}
+
+.focus-summary-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 0.6em;
+ margin-top: 0.5em;
+}
+
+.focus-summary-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.5em 0.75em;
+ border-radius: 6px;
+ background: rgba(0, 0, 0, 0.04);
+}
+
+.dark-mode .focus-summary-row {
+ background: rgba(255, 255, 255, 0.06);
+}
+
+.focus-summary-label {
+ font-size: 0.9em;
+ opacity: 0.75;
+}
+
+.focus-summary-value {
+ font-weight: 700;
+ font-size: 0.95em;
+}
+
+.focus-summary-value.focus-on-topic {
+ color: #1a8a3a;
+}
+
+.dark-mode .focus-summary-value.focus-on-topic {
+ color: #4cd964;
+}
+
+.focus-summary-value.focus-off-topic {
+ color: #c0392b;
+}
+
+.dark-mode .focus-summary-value.focus-off-topic {
+ color: #ff6b6b;
+}
diff --git a/index.html b/index.html
index d0e97bc17..1b47cb3c3 100644
--- a/index.html
+++ b/index.html
@@ -140,6 +140,7 @@
+
+
+
+
+
What do you want to focus on today?
+
Enter a goal, topic, or keywords (e.g. "learning React hooks")
+
+
+
+
+
+
+
+
+
+ ⚠
+ Looks like you've drifted. Your goal: . Keep going or refocus?
+
+
+
+
+
+
+
+
+
Focus Session Complete
+
+
+
+ Total session
+ 0s
+
+
+ On-topic time
+ 0s
+
+
+ Off-track time
+ 0s
+
+
+ Drift alerts
+ 0
+
+
+
+
diff --git a/js/default.js b/js/default.js
index acacba620..4729227b8 100644
--- a/js/default.js
+++ b/js/default.js
@@ -184,5 +184,8 @@ require('searchbar/developmentModeNotification.js').initialize()
require('searchbar/shortcutButtons.js').initialize()
require('searchbar/calculatorPlugin.js').initialize()
+require('focusMode.js').initialize()
+
// once everything's loaded, start the session
require('sessionRestore.js').restore()
+require('focusMode.js').onSessionRestoreComplete()
diff --git a/js/focusMode.js b/js/focusMode.js
index 7a4f171b4..67ae953d6 100644
--- a/js/focusMode.js
+++ b/js/focusMode.js
@@ -1,20 +1,424 @@
-var isFocusMode = false
+var settings = require('util/settings/settings.js')
+var webviews = require('webviews.js')
-ipc.on('enterFocusMode', function () {
- isFocusMode = true
- document.body.classList.add('is-focus-mode')
-})
+/* ─── Stop words ─────────────────────────────────────────────────────────── */
-ipc.on('exitFocusMode', function () {
- isFocusMode = false
- document.body.classList.remove('is-focus-mode')
-})
+var STOP_WORDS = new Set([
+ 'a', 'an', 'the', 'is', 'are', 'was', 'for', 'to', 'of', 'and', 'or',
+ 'in', 'on', 'at', 'with', 'it', 'this', 'that', 'by', 'from', 'be',
+ 'as', 'how', 'what', 'about', 'i', 'my', 'me'
+])
-module.exports = {
- enabled: function () {
- return isFocusMode
- },
- warn: function () {
- ipc.invoke('showFocusModeDialog2')
+/* ─── Tokenizer ──────────────────────────────────────────────────────────── */
+
+function tokenize (text) {
+ if (!text) return []
+ var words = text.toLowerCase()
+ .replace(/[^a-z0-9\s]/g, ' ')
+ .split(/\s+/)
+ .filter(function (w) { return w.length > 1 && !STOP_WORDS.has(w) })
+
+ var bigrams = []
+ for (var i = 0; i < words.length - 1; i++) {
+ bigrams.push(words[i] + ' ' + words[i + 1])
+ }
+ return words.concat(bigrams)
+}
+
+/* ─── Relevance scorer ───────────────────────────────────────────────────── */
+
+function scoreRelevance (signals, goalTokens) {
+ var combined = signals.join(' ').toLowerCase()
+ var score = 0
+ goalTokens.forEach(function (token) {
+ if (combined.indexOf(token) !== -1) score++
+ })
+ return score
+}
+
+/* ─── Session state ──────────────────────────────────────────────────────── */
+
+var state = {
+ enabled: false,
+ goal: '',
+ goalTokens: [],
+ sessionStart: null,
+ consecutiveOffTopic: 0,
+ lastAlertTime: 0,
+ offTopicSeconds: 0,
+ offTopicStartTime: null,
+ currentPageOnTopic: true,
+ driftAlerts: 0,
+ samplingInterval: null,
+ timerInterval: null,
+ windowFocused: true,
+ sessionRestoreComplete: false
+}
+
+/* ─── UI element references ──────────────────────────────────────────────── */
+
+var ui = {}
+
+function getUIElements () {
+ ui.indicator = document.getElementById('focus-mode-indicator')
+ ui.goalModal = document.getElementById('focus-mode-goal-modal')
+ ui.goalInput = document.getElementById('focus-mode-goal-input')
+ ui.alertBar = document.getElementById('focus-mode-alert')
+ ui.alertGoal = document.getElementById('focus-alert-goal')
+ ui.summaryModal = document.getElementById('focus-mode-summary')
+ ui.summaryTotal = document.getElementById('focus-summary-total')
+ ui.summaryOnTopic = document.getElementById('focus-summary-ontopic')
+ ui.summaryOffTopic = document.getElementById('focus-summary-offtopic')
+ ui.summaryAlerts = document.getElementById('focus-summary-alerts')
+}
+
+/* ─── Indicator ──────────────────────────────────────────────────────────── */
+
+function currentOffTopicSeconds () {
+ var extra = 0
+ if (state.offTopicStartTime && state.windowFocused) {
+ extra = Math.round((Date.now() - state.offTopicStartTime) / 1000)
+ }
+ return state.offTopicSeconds + extra
+}
+
+function updateIndicator () {
+ if (!ui.indicator) return
+ if (!state.enabled) {
+ ui.indicator.hidden = true
+ return
+ }
+ ui.indicator.hidden = false
+ var mins = Math.floor(currentOffTopicSeconds() / 60)
+ if (mins > 0) {
+ ui.indicator.textContent = mins + ' min off-track'
+ ui.indicator.classList.add('is-off-track')
+ } else {
+ ui.indicator.textContent = 'On track'
+ ui.indicator.classList.remove('is-off-track')
+ }
+}
+
+/* ─── Time formatter ─────────────────────────────────────────────────────── */
+
+function formatTime (seconds) {
+ var m = Math.floor(seconds / 60)
+ var s = seconds % 60
+ if (m > 0) return m + 'm ' + s + 's'
+ return s + 's'
+}
+
+/* ─── Modal helpers ──────────────────────────────────────────────────────── */
+
+function getModalMode () {
+ return require('modalMode.js')
+}
+
+function showGoalModal () {
+ if (!ui.goalModal) return
+ webviews.requestPlaceholder('focusMode')
+ ui.goalModal.hidden = false
+ // pre-fill with current goal so the user can see/update it
+ ui.goalInput.value = state.goal || localStorage.getItem('focusModeGoal') || ''
+ ui.goalInput.focus()
+ ui.goalInput.select()
+}
+
+function hideGoalModal () {
+ if (!ui.goalModal) return
+ ui.goalModal.hidden = true
+ webviews.hidePlaceholder('focusMode')
+}
+
+function showSummaryModal (totalSec, onSec, offSec, alerts) {
+ if (!ui.summaryModal) return
+ ui.summaryTotal.textContent = formatTime(totalSec)
+ ui.summaryOnTopic.textContent = formatTime(onSec)
+ ui.summaryOffTopic.textContent = formatTime(offSec)
+ ui.summaryAlerts.textContent = alerts
+
+ webviews.requestPlaceholder('focusMode')
+ ui.summaryModal.hidden = false
+ getModalMode().toggle(true, {
+ onDismiss: function () {
+ ui.summaryModal.hidden = true
+ webviews.hidePlaceholder('focusMode')
+ getModalMode().toggle(false)
+ }
+ })
+}
+
+/* ─── Alert bar ──────────────────────────────────────────────────────────── */
+
+var alertAutoHideTimer = null
+
+function showAlert () {
+ if (!ui.alertBar) return
+ if (ui.alertGoal) ui.alertGoal.textContent = state.goal
+ ui.alertBar.hidden = false
+
+ if (alertAutoHideTimer) clearTimeout(alertAutoHideTimer)
+ alertAutoHideTimer = setTimeout(function () {
+ if (ui.alertBar) ui.alertBar.hidden = true
+ }, 10000)
+}
+
+/* ─── Relevance check ────────────────────────────────────────────────────── */
+
+function checkRelevance (url, title, meta) {
+ if (!state.enabled || state.goalTokens.length === 0) return
+
+ var signals = [url || '', title || '', meta || '']
+ var score = scoreRelevance(signals, state.goalTokens)
+ var isOnTopic = score >= 1
+
+ if (isOnTopic) {
+ if (state.offTopicStartTime) {
+ state.offTopicSeconds += Math.round((Date.now() - state.offTopicStartTime) / 1000)
+ state.offTopicStartTime = null
+ }
+ state.consecutiveOffTopic = 0
+ state.currentPageOnTopic = true
+ } else {
+ if (!state.offTopicStartTime && state.windowFocused) {
+ state.offTopicStartTime = Date.now()
+ }
+ state.consecutiveOffTopic++
+ state.currentPageOnTopic = false
+
+ if (state.consecutiveOffTopic >= 2) {
+ var now = Date.now()
+ if (now - state.lastAlertTime > 3 * 60 * 1000) {
+ showAlert()
+ state.lastAlertTime = now
+ state.driftAlerts++
+ }
+ state.consecutiveOffTopic = 0
+ }
+ }
+
+ updateIndicator()
+}
+
+/* ─── Page content sampler (every 45 s) ─────────────────────────────────── */
+
+function sampleCurrentPage () {
+ if (!state.enabled) return
+ var tabId = tabs.getSelected()
+ if (!tabId) return
+ var tab = tabs.get(tabId)
+ if (!tab || !tab.url) return
+ if (tab.url.indexOf('min://') === 0 || tab.url.indexOf('about:') === 0) return
+
+ var code = [
+ '(function(){',
+ ' var m = document.querySelector(\'meta[name="description"]\');',
+ ' return {',
+ ' title: document.title || "",',
+ ' meta: m ? (m.getAttribute("content") || "") : "",',
+ ' url: window.location.href || ""',
+ ' };',
+ '})()'
+ ].join('\n')
+
+ webviews.callAsync(tabId, 'executeJavaScript', [code], function (err, result) {
+ if (!err && result) {
+ checkRelevance(result.url, result.title, result.meta)
+ }
+ })
+}
+
+/* ─── Session lifecycle ──────────────────────────────────────────────────── */
+
+function startSession (goal) {
+ state.goal = goal
+ state.goalTokens = tokenize(goal)
+ state.sessionStart = Date.now()
+ state.consecutiveOffTopic = 0
+ state.lastAlertTime = 0
+ state.offTopicSeconds = 0
+ state.offTopicStartTime = null
+ state.currentPageOnTopic = true
+ state.driftAlerts = 0
+
+ localStorage.setItem('focusModeGoal', goal)
+
+ if (state.samplingInterval) clearInterval(state.samplingInterval)
+ state.samplingInterval = setInterval(sampleCurrentPage, 45000)
+
+ if (state.timerInterval) clearInterval(state.timerInterval)
+ state.timerInterval = setInterval(updateIndicator, 5000)
+
+ sampleCurrentPage()
+ updateIndicator()
+}
+
+function endSession () {
+ if (state.samplingInterval) { clearInterval(state.samplingInterval); state.samplingInterval = null }
+ if (state.timerInterval) { clearInterval(state.timerInterval); state.timerInterval = null }
+
+ if (state.offTopicStartTime) {
+ state.offTopicSeconds += Math.round((Date.now() - state.offTopicStartTime) / 1000)
+ state.offTopicStartTime = null
+ }
+
+ var totalSec = state.sessionStart ? Math.round((Date.now() - state.sessionStart) / 1000) : 0
+ var offSec = state.offTopicSeconds
+ var onSec = Math.max(0, totalSec - offSec)
+
+ showSummaryModal(totalSec, onSec, offSec, state.driftAlerts)
+
+ state.enabled = false
+ state.sessionStart = null
+ state.goal = ''
+ state.goalTokens = []
+ localStorage.removeItem('focusModeGoal')
+ updateIndicator()
+}
+
+/* ─── Enable / disable ───────────────────────────────────────────────────── */
+
+function enable () {
+ state.enabled = true
+ updateIndicator()
+}
+
+function disable () {
+ if (state.sessionStart) {
+ endSession()
+ } else {
+ state.enabled = false
+ updateIndicator()
}
}
+
+/* ─── Window blur / focus ────────────────────────────────────────────────── */
+
+function onWindowBlur () {
+ state.windowFocused = false
+ if (state.offTopicStartTime) {
+ state.offTopicSeconds += Math.round((Date.now() - state.offTopicStartTime) / 1000)
+ state.offTopicStartTime = null
+ }
+}
+
+function onWindowFocus () {
+ state.windowFocused = true
+ if (state.enabled && !state.currentPageOnTopic && !state.offTopicStartTime) {
+ state.offTopicStartTime = Date.now()
+ }
+}
+
+/* ─── Initialize ─────────────────────────────────────────────────────────── */
+
+function initialize () {
+ getUIElements()
+
+ ipc.on('blur', onWindowBlur)
+ ipc.on('focus', onWindowFocus)
+
+ // Show goal modal on every new blank tab while Focus Mode is ON
+ tasks.on('tab-added', function (tabId, tab) {
+ if (!state.enabled) return
+ if (!state.sessionRestoreComplete) return // don't show during startup restore
+ if (tab && tab.url) return // skip tabs opened with a URL (link/bookmark)
+ // small delay so the tab UI settles before the modal appears
+ setTimeout(function () {
+ if (state.enabled) showGoalModal()
+ }, 150)
+ })
+
+ // Intercept tab URL changes on the active tab
+ tasks.on('tab-updated', function (id, key) {
+ if (!state.enabled) return
+ if (key === 'url' && id === tabs.getSelected()) {
+ var tab = tabs.get(id)
+ if (!tab || !tab.url) return
+ var url = tab.url
+ if (url.indexOf('min://') === 0 || url.indexOf('about:') === 0) return
+ checkRelevance(url, tab.title || '', '')
+ }
+ })
+
+ // Goal modal — submit button
+ document.getElementById('focus-goal-submit').addEventListener('click', function () {
+ var goal = ui.goalInput.value.trim()
+ if (!goal) return
+ hideGoalModal()
+ startSession(goal)
+ })
+
+ // Goal modal — Enter key
+ ui.goalInput.addEventListener('keydown', function (e) {
+ if (e.key === 'Enter') {
+ var goal = this.value.trim()
+ if (!goal) return
+ hideGoalModal()
+ startSession(goal)
+ } else if (e.key === 'Escape') {
+ hideGoalModal()
+ }
+ })
+
+ // Goal modal — Dismiss (×)
+ document.getElementById('focus-goal-dismiss').addEventListener('click', function () {
+ hideGoalModal()
+ })
+
+ // Goal modal — Open Preferences
+ document.getElementById('focus-goal-open-prefs').addEventListener('click', function () {
+ hideGoalModal()
+ webviews.update(tabs.getSelected(), 'min://app/pages/settings/index.html')
+ })
+
+ // Alert bar — Ignore
+ document.getElementById('focus-alert-ignore').addEventListener('click', function () {
+ if (ui.alertBar) ui.alertBar.hidden = true
+ })
+
+ // Alert bar — Refocus (open a new blank tab)
+ document.getElementById('focus-alert-refocus').addEventListener('click', function () {
+ if (ui.alertBar) ui.alertBar.hidden = true
+ require('browserUI.js').addTab()
+ })
+
+ // Summary close button
+ document.getElementById('focus-summary-close').addEventListener('click', function () {
+ if (ui.summaryModal) ui.summaryModal.hidden = true
+ webviews.hidePlaceholder('focusMode')
+ getModalMode().toggle(false)
+ })
+
+ // React to settings toggle (from settings page)
+ var _initialLoad = true
+ settings.listen('focusModeEnabled', function (value) {
+ if (_initialLoad) {
+ _initialLoad = false
+ if (value === true) enable()
+ return
+ }
+ if (value === true && !state.enabled) {
+ enable()
+ } else if (!value && state.enabled) {
+ disable()
+ }
+ })
+
+ updateIndicator()
+}
+
+/* ─── Public API ─────────────────────────────────────────────────────────── */
+
+module.exports = {
+ initialize: initialize,
+ enabled: function () { return state.enabled },
+ warn: function () { ipc.invoke('showFocusModeDialog2') },
+ enable: enable,
+ disable: disable,
+ startSession: startSession,
+ endSession: endSession,
+ tokenize: tokenize,
+ scoreRelevance: scoreRelevance,
+ checkRelevance: checkRelevance,
+ onSessionRestoreComplete: function () { state.sessionRestoreComplete = true }
+}
diff --git a/pages/settings/index.html b/pages/settings/index.html
index d8e6d629c..83a878ee1 100644
--- a/pages/settings/index.html
+++ b/pages/settings/index.html
@@ -234,6 +234,19 @@
+
+
Focus Mode
+
+
+
+
+
+ Tracks your browsing against a session goal and alerts you when you drift off-topic.
+ All tracking is local — nothing leaves your device.
+
+
+
+
diff --git a/pages/settings/settings.js b/pages/settings/settings.js
index 64005305f..b2e014f63 100644
--- a/pages/settings/settings.js
+++ b/pages/settings/settings.js
@@ -449,6 +449,18 @@ searchEngineInput.addEventListener('input', function (e) {
settings.set('searchEngine', { url: this.value })
})
+/* focus mode setting */
+
+var focusModeCheckbox = document.getElementById('checkbox-focus-mode')
+
+settings.get('focusModeEnabled', function (value) {
+ focusModeCheckbox.checked = !!value
+})
+
+focusModeCheckbox.addEventListener('change', function () {
+ settings.set('focusModeEnabled', this.checked)
+})
+
/* key map settings */
settings.get('keyMap', function (keyMapSettings) {
diff --git a/scripts/buildBrowserStyles.js b/scripts/buildBrowserStyles.js
index ded9b3145..740acbc87 100644
--- a/scripts/buildBrowserStyles.js
+++ b/scripts/buildBrowserStyles.js
@@ -20,7 +20,8 @@ const modules = [
'css/passwordManager.css',
'css/passwordCapture.css',
'css/passwordViewer.css',
- 'node_modules/dragula/dist/dragula.min.css'
+ 'node_modules/dragula/dist/dragula.min.css',
+ 'css/focusMode.css'
]
function buildBrowserStyles () {