diff --git a/index.html b/index.html
new file mode 100644
index 0000000..2c39f2e
--- /dev/null
+++ b/index.html
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/js/app_window.js b/js/app_window.js
new file mode 100644
index 0000000..a4a74a1
--- /dev/null
+++ b/js/app_window.js
@@ -0,0 +1,241 @@
+const AppWindow = {
+ _id: 0,
+
+ containerElement: document.getElementById('windows'),
+ statusbar: document.getElementById('statusbar'),
+ softwareButtons: document.getElementById('software-buttons'),
+ softwareBackButton: document.getElementById('software-back-button'),
+ softwareHomeButton: document.getElementById('software-home-button'),
+ dock: document.getElementById('dock'),
+
+ HIDDEN_ROLES: [ 'system', 'homescreen' ],
+
+ init: function () {
+ this.softwareBackButton.addEventListener('click', this.onButtonClick.bind(this));
+ this.softwareHomeButton.addEventListener('click', this.onButtonClick.bind(this));
+ },
+
+ create: async function (manifestUrl, options) {
+ var existingWindow = this.containerElement.querySelector(`[data-manifest-url="${manifestUrl}"]`);
+ if (existingWindow) {
+ if (options.originPos) {
+ if (this.homescreenElement) {
+ this.homescreenElement.style.transformOrigin = `${options.originPos.x}px ${options.originPos.y}px`;
+ }
+ existingWindow.style.transformOrigin = `${options.originPos.x}px ${options.originPos.y}px`;
+ }
+ this.unminimize(existingWindow.id);
+ return;
+ }
+
+ const windowId = `appframe${AppWindow._id}`;
+ console.log(windowId + ': ' + manifestUrl);
+ AppWindow._id++;
+
+ var manifest;
+ await fetch(manifestUrl)
+ .then(response => response.json())
+ .then(function (data) {
+ manifest = data;
+ // You can perform further operations with the 'manifest' variable here
+ })
+ .catch(function (error) {
+ console.log('Error fetching manifest:', error);
+ });
+
+ // Apply window options
+ const windowOptions = Object.assign(
+ {
+ start_url: manifest.start_url,
+ launch_path: manifest.launch_path,
+ width: manifest.width,
+ height: manifest.height,
+ transparent: manifest.transparent,
+ cli_args: ''
+ },
+ options
+ );
+
+ // Create dock icon
+ if (this.HIDDEN_ROLES.indexOf(manifest.role) == -1) {
+ const icon = document.createElement('div');
+ icon.classList.add('icon');
+ icon.dataset.manifestUrl = manifestUrl;
+ icon.onclick = () => {
+ this.focus(windowId);
+ };
+ this.dock.appendChild(icon);
+
+ icon.classList.add('expand');
+ icon.addEventListener('animationend', () => {
+ icon.classList.remove('expand');
+ });
+
+ const iconImage = document.createElement('img');
+ Object.entries(manifest.icons).forEach(entry => {
+ if (entry[0] >= this.DOCK_ICON_SIZE) {
+ return;
+ }
+ const url = new URL(manifestUrl);
+ iconImage.src = url.origin + entry[1];
+ });
+ icon.appendChild(iconImage);
+ }
+
+ // Create window container
+ const windowDiv = document.createElement('div');
+ windowDiv.dataset.manifestUrl = manifestUrl;
+ if (manifest.role == 'homescreen') {
+ windowDiv.id = 'homescreen';
+ AppWindow.homescreenElement = windowDiv;
+ } else {
+ windowDiv.id = windowId;
+ }
+ windowDiv.classList.add('appframe');
+ if (manifest.statusbar && manifest.statusbar !== 'normal') {
+ windowDiv.classList.add(manifest.statusbar);
+ }
+ if (manifest.display && manifest.display !== 'standalone') {
+ windowDiv.classList.add(manifest.display);
+ }
+ if (windowOptions.transparent) {
+ windowDiv.classList.add('transparent');
+ }
+ if (windowOptions.originPos) {
+ if (this.homescreenElement) {
+ this.homescreenElement.style.transformOrigin = `${windowOptions.originPos.x}px ${windowOptions.originPos.y}px`;
+ }
+ windowDiv.style.transformOrigin = `${windowOptions.originPos.x}px ${windowOptions.originPos.y}px`;
+ }
+ this.containerElement.appendChild(windowDiv);
+
+ // Focus the app window
+ this.focus(windowDiv.id);
+
+ windowDiv.classList.add('expand');
+ windowDiv.addEventListener('animationend', () => {
+ windowDiv.classList.remove('expand');
+ });
+
+ // Create chrome
+ var chromeContainer = document.createElement('div');
+ chromeContainer.classList.add('chrome');
+ windowDiv.appendChild(chromeContainer);
+
+ var isChromeEnabled = false;
+ if (manifest.chrome && manifest.chrome.navigation) {
+ isChromeEnabled = true;
+ }
+
+ if (manifest.start_url) {
+ Browser.init(chromeContainer, manifest.start_url, isChromeEnabled);
+ } else {
+ if (manifest.launch_path) {
+ var url = new URL(manifestUrl);
+ Browser.init(chromeContainer, url.origin + manifest.launch_path, isChromeEnabled);
+ }
+ }
+ },
+
+ focus: function (id) {
+ var windowDiv = document.getElementById(id);
+ var manifestUrl = windowDiv.dataset.manifestUrl;
+ var dockIcon = this.dock.querySelector(`[data-manifest-url="${manifestUrl}"]`);
+
+ this.containerElement.querySelectorAll('.appframe').forEach((element) => {
+ element.classList.remove('active');
+ });
+ this.dock.querySelectorAll('.icon').forEach((element) => {
+ element.classList.remove('active');
+ });
+
+ windowDiv.classList.add('active');
+ if (dockIcon) {
+ dockIcon.classList.add('active');
+ }
+ this.focusedWindow = windowDiv;
+ },
+
+ close: function (id) {
+ if (id === 'homescreen') {
+ return;
+ }
+ var windowDiv = document.getElementById(id);
+ var manifestUrl = windowDiv.dataset.manifestUrl;
+ var dockIcon = this.dock.querySelector(`[data-manifest-url="${manifestUrl}"]`);
+
+ windowDiv.classList.add('shrink');
+ if (dockIcon) {
+ dockIcon.classList.add('shrink');
+ }
+ windowDiv.addEventListener('animationend', () => {
+ windowDiv.classList.remove('shrink');
+ windowDiv.remove();
+ if (dockIcon) {
+ dockIcon.classList.remove('shrink');
+ dockIcon.remove();
+ }
+ this.focus('homescreen');
+ });
+ },
+
+ minimize: function (id) {
+ if (id === 'homescreen') {
+ return;
+ }
+ var windowDiv = document.getElementById(id);
+ var manifestUrl = windowDiv.dataset.manifestUrl;
+ var dockIcon = this.dock.querySelector(`[data-manifest-url="${manifestUrl}"]`);
+
+ windowDiv.classList.add('shrink');
+ if (dockIcon) {
+ dockIcon.classList.add('minimized');
+ }
+ windowDiv.addEventListener('animationend', () => {
+ windowDiv.classList.remove('active');
+ windowDiv.classList.remove('shrink');
+ this.focus('homescreen');
+ });
+ },
+
+ unminimize: function (id) {
+ if (id === 'homescreen') {
+ return;
+ }
+ var windowDiv = document.getElementById(id);
+ var manifestUrl = windowDiv.dataset.manifestUrl;
+ var dockIcon = this.dock.querySelector(`[data-manifest-url="${manifestUrl}"]`);
+
+ windowDiv.classList.add('active');
+ windowDiv.classList.add('expand');
+ if (dockIcon) {
+ dockIcon.classList.remove('minimized');
+ }
+ windowDiv.addEventListener('animationend', () => {
+ windowDiv.classList.remove('expand');
+ this.focus(id);
+ });
+ },
+
+ onButtonClick: function (event) {
+ switch (event.target) {
+ case this.softwareBackButton:
+ var webview = this.focusedWindow.querySelector('.browser.active');
+ if (webview.canGoBack()) {
+ webview.goBack();
+ } else {
+ this.close(this.focusedWindow.id);
+ }
+ break;
+
+ case this.softwareHomeButton:
+ this.minimize(this.focusedWindow.id);
+ break;
+
+ default:
+ break;
+ }
+ },
+};
+
+AppWindow.init();
diff --git a/js/battery_icon.js b/js/battery_icon.js
new file mode 100644
index 0000000..2eebc83
--- /dev/null
+++ b/js/battery_icon.js
@@ -0,0 +1,33 @@
+const BatteryIcon = {
+ iconElement: document.getElementById("statusbar-battery"),
+
+ init: function () {
+ navigator.getBattery().then((battery) => {
+ this.battery = battery;
+
+ this.iconElement.classList.remove("hidden");
+
+ var level = battery.level;
+ var charging = battery.charging;
+ if (charging) {
+ this.iconElement.dataset.icon = `battery-charging-${Math.round(level * 10) * 10}`;
+ } else {
+ this.iconElement.dataset.icon = `battery-${Math.round(level * 10) * 10}`;
+ }
+
+ ['chargingchange', 'dischargingchange', 'levelchange'].forEach(event => {
+ battery.addEventListener(event, () => {
+ level = battery.level;
+ charging = battery.isCharging;
+ if (charging) {
+ this.iconElement.dataset.icon = `battery-charging-${Math.round(level * 10) * 10}`;
+ } else {
+ this.iconElement.dataset.icon = `battery-${Math.round(level * 10) * 10}`;
+ }
+ });
+ });
+ });
+ }
+}
+
+BatteryIcon.init();
diff --git a/js/bletooth_icon.js b/js/bletooth_icon.js
new file mode 100644
index 0000000..365003c
--- /dev/null
+++ b/js/bletooth_icon.js
@@ -0,0 +1,32 @@
+
+const BluetoothIcon = {
+ iconElement: document.getElementById("statusbar-bluetooth"),
+
+ init: function () {
+ this.update();
+ },
+
+ update: function () {
+ si.bluetoothDevices((err, data) => {
+ if (err) {
+ console.error(err);
+ } else {
+ const connectedBluetooth = networks.find(network => network.state === 'connected');
+
+ const bluetoothEnabled = (connectedBluetooth) || false;
+ console.log("Bluetooth Enabled:", bluetoothEnabled);
+
+ if (bluetoothEnabled) {
+ this.iconElement.classList.remove("hidden");
+ } else {
+ this.iconElement.classList.add("hidden");
+ }
+ }
+ });
+
+ clearTimeout(this.timer);
+ this.timer = setTimeout(this.update, 1000);
+ },
+};
+
+BluetoothIcon.init();
diff --git a/js/bootstrap.js b/js/bootstrap.js
new file mode 100644
index 0000000..6600e2d
--- /dev/null
+++ b/js/bootstrap.js
@@ -0,0 +1,8 @@
+const path = require('path');
+const si = require("systeminformation");
+
+document.addEventListener('DOMContentLoaded', function () {
+ if (document.readyState === "complete") {}
+
+ AppWindow.create('http://homescreen.localhost:8081/manifest.json');
+});
diff --git a/js/browser/browser.js b/js/browser/browser.js
new file mode 100644
index 0000000..e69de29
diff --git a/js/chrome.js b/js/chrome.js
new file mode 100644
index 0000000..a0e990a
--- /dev/null
+++ b/js/chrome.js
@@ -0,0 +1,330 @@
+const Browser = {
+ chrome: document.getElementById('chrome'),
+ DEFAULT_URL: 'https://www.duckduckgo.com',
+
+ tablist: function() {
+ return this.chrome.querySelector('.tablist');
+ },
+
+ addButton: function() {
+ return this.chrome.querySelector('.add-button');
+ },
+
+ navbarBackButton: function() {
+ return this.chrome.querySelector('.navbar-back-button');
+ },
+
+ navbarForwardButton: function() {
+ return this.chrome.querySelector('.navbar-forward-button');
+ },
+
+ navbarReloadButton: function() {
+ return this.chrome.querySelector('.navbar-reload-button');
+ },
+
+ navbarHomeButton: function() {
+ return this.chrome.querySelector('.navbar-home-button');
+ },
+
+ urlbar: function() {
+ return this.chrome.querySelector('.urlbar');
+ },
+
+ urlbarInput: function() {
+ return this.chrome.querySelector('.urlbar-input');
+ },
+
+ urlbarDisplayUrl: function() {
+ return this.chrome.querySelector('.urlbar-display-url');
+ },
+
+ browserContainer: function() {
+ return this.chrome.querySelector('.browser-container');
+ },
+
+ init: function(chromeElement, url, isChromeEnabled) {
+ if (chromeElement) {
+ this.chrome = chromeElement;
+ this.chrome.innerHTML = `
+
+
+ `;
+ }
+ if (isChromeEnabled) {
+ this.chrome.classList.add('visible');
+ }
+ this.openNewTab(false, url);
+
+ this.addButton().addEventListener('click', this.openNewTab.bind(this, false));
+ this.urlbarInput().addEventListener('keydown', this.handleUrlbarInputKeydown.bind(this));
+ this.navbarBackButton().addEventListener('click', this.handleNavbarBackButton.bind(this));
+ this.navbarForwardButton().addEventListener('click', this.handleNavbarForwardButton.bind(this));
+ this.navbarReloadButton().addEventListener('click', this.handleNavbarReloadButton.bind(this));
+ this.navbarHomeButton().addEventListener('click', this.handleNavbarHomeButton.bind(this));
+ },
+
+ openNewTab: function(isPrivate, url) {
+ var tab = document.createElement('li');
+ this.tablist().appendChild(tab);
+
+ var favicon = document.createElement('img');
+ favicon.classList.add('favicon');
+ tab.appendChild(favicon);
+
+ var title = document.createElement('span');
+ title.classList.add('title');
+ tab.appendChild(title);
+
+ var closeButton = document.createElement('button');
+ closeButton.classList.add('close-button');
+ closeButton.dataset.icon = 'close';
+ tab.appendChild(closeButton);
+
+ var webview = document.createElement('webview');
+ webview.src = url || this.DEFAULT_URL;
+ webview.classList.add('browser');
+ webview.nodeintegration = true;
+ webview.nodeintegrationinsubframes = true;
+ webview.disablewebsecurity = true;
+ webview.webpreferences = "contextIsolation=false";
+ webview.useragent = navigator.userAgent;
+ webview.preload = `file://./preload.js`;
+ this.browserContainer().appendChild(webview);
+
+ webview.addEventListener('context-menu', this.handleContextMenu.bind(this));
+ webview.addEventListener('page-favicon-updated', this.handlePageFaviconUpdated.bind(this));
+ webview.addEventListener('page-title-updated', this.handlePageTitleUpdated.bind(this));
+ webview.addEventListener('did-start-navigation', this.handleDidStartNavigation.bind(this));
+ webview.addEventListener('did-change-theme-color', this.handleThemeColorUpdated.bind(this));
+ webview.addEventListener('', this.handleThemeColorUpdated.bind(this));
+
+ const ipcListener = EventListener.appWindow;
+ const pattern = /^http:\/\/.*\.localhost:8081\//;
+ const cssURL = `http://shared.localhost:${location.port}/style/webview.css`;
+ const jsURL = `http://shared.localhost:${location.port}/js/webview.js`;
+
+
+ ['did-start-loading', 'did-start-navigation', 'did-stop-loading', 'dom-ready'].forEach((eventType) => {
+ webview.addEventListener(eventType, () => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', cssURL, true);
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ const cssContent = xhr.responseText;
+ webview.insertCSS(cssContent);
+ } else if (xhr.readyState === 4) {
+ console.error('Failed to fetch CSS:', xhr.status, xhr.statusText);
+ }
+ };
+ xhr.send();
+
+ const xhr1 = new XMLHttpRequest();
+ xhr1.open('GET', jsURL, true);
+ xhr1.onreadystatechange = function () {
+ if (xhr1.readyState === 4 && xhr1.status === 200) {
+ const jsContent = xhr1.responseText;
+ webview.executeJavaScript(jsContent);
+ } else if (xhr1.readyState === 4) {
+ console.error('Failed to fetch JS:', xhr1.status, xhr1.statusText);
+ }
+ };
+ xhr1.send();
+
+ if (pattern.test(webview.getURL())) {
+ webview.nodeintegration = true;
+ webview.nodeintegrationinsubframes = true;
+ webview.disablewebsecurity = true;
+ webview.webpreferences = "contextIsolation=false";
+ webview.addEventListener('ipc-message', ipcListener);
+ } else {
+ webview.nodeintegration = false;
+ webview.nodeintegrationinsubframes = false;
+ webview.disablewebsecurity = false;
+ webview.webpreferences = "contextIsolation=true";
+ webview.removeEventListener('ipc-message', ipcListener);
+ }
+ });
+ });
+
+ const focus = () => {
+ var tabs = this.chrome.querySelectorAll('.tablist li');
+ tabs.forEach(function(tab) {
+ tab.classList.remove('active');
+ });
+
+ var webviews = this.chrome.querySelectorAll('.browser-container webview');
+ webviews.forEach(function(webview) {
+ webview.classList.remove('active');
+ });
+
+ tab.classList.add('active');
+ webview.classList.add('active');
+ };
+
+ focus();
+ tab.addEventListener('click', focus.bind(this));
+ closeButton.addEventListener('click', () => {
+ tab.remove();
+ webview.remove();
+ });
+ },
+
+ handleUrlbarInputKeydown: function(event) {
+ if (event.key === 'Enter') {
+ var activeTab = this.chrome.querySelector('.tablist li.active');
+ var webview = this.chrome.querySelector('.browser-container .browser.active');
+ var url = event.target.value;
+ webview.src = url;
+ }
+ },
+
+ handleNavbarBackButton: function() {
+ var webview = this.chrome.querySelector('.browser-container .browser.active');
+ if (webview.canGoBack()) {
+ webview.goBack();
+ }
+ },
+
+ handleNavbarForwardButton: function() {
+ var webview = this.chrome.querySelector('.browser-container .browser.active');
+ if (webview.canGoForward()) {
+ webview.goForward();
+ }
+ },
+
+ handleNavbarReloadButton: function() {
+ var webview = this.chrome.querySelector('.browser-container .browser.active');
+ webview.reload();
+ },
+
+ handleNavbarHomeButton: function() {
+ var webview = this.chrome.querySelector('.browser-container .browser.active');
+ webview.src = this.DEFAULT_URL;
+ },
+
+ handleContextMenu: function(event) {
+ console.log(event);
+ contextMenu(event.params.x, event.params.y, [
+ {
+ name: 'Copy',
+ disabled: !event.params.editFlags.canCopy,
+ onclick: () => {
+ webview.focus();
+ webview.copy();
+ },
+ },
+ {
+ name: 'Cut',
+ disabled: !event.params.editFlags.canCut,
+ onclick: () => {
+ webview.focus();
+ webview.cut();
+ },
+ },
+ {
+ name: 'Paste',
+ disabled: !event.params.editFlags.canPaste,
+ onclick: () => {
+ webview.focus();
+ webview.paste();
+ },
+ },
+ {
+ name: 'Select All',
+ disabled: !event.params.editFlags.canSelectAll,
+ onclick: () => {
+ webview.focus();
+ webview.selectAll();
+ },
+ },
+ {
+ name: 'Delete',
+ disabled: !event.params.editFlags.canDelete,
+ onclick: () => {
+ webview.focus();
+ webview.delete();
+ },
+ },
+ ]);
+ },
+
+ handlePageFaviconUpdated: function(event) {
+ var favicon = this.chrome.querySelector('.tablist .active .favicon');
+ favicon.src = event.favicons[0];
+ },
+
+ handlePageTitleUpdated: function(event) {
+ var title = this.chrome.querySelector('.tablist .active .title');
+ title.textContent = event.title;
+ },
+
+ handleDidStartNavigation: function() {
+ var webview = this.chrome.querySelector('.browser-container .browser.active');
+ this.urlbarInput().value = webview.getURL();
+ var url = new URL(webview.getURL());
+ this.urlbarDisplayUrl().innerHTML = `
+ ${url.protocol}//
+ ${url.host}
+ ${url.pathname}
+ ${url.search}
+ ${url.hash}
+ `;
+ },
+
+ handleThemeColorUpdated: function(event) {
+ var webview = this.chrome.querySelector('.browser-container .browser.active');
+ const color = event.themeColor;
+ webview.dataset.themeColor = color;
+ this.chrome.style.setProperty('--theme-color', color);
+
+ // Calculate the luminance of the color
+ const luminance = this.calculateLuminance(color);
+
+ // If the color is light (luminance > 0.5), add 'light' class to the status bar
+ if (luminance > 0.5) {
+ this.statusbar.classList.add('light');
+ this.softwareButtons.classList.add('light');
+ } else {
+ // Otherwise, remove 'light' class
+ this.statusbar.classList.remove('light');
+ this.softwareButtons.classList.remove('light');
+ }
+ },
+
+ calculateLuminance: function (color) {
+ // Convert the color to RGB values
+ const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
+ const r = parseInt(rgb[1], 16);
+ const g = parseInt(rgb[2], 16);
+ const b = parseInt(rgb[3], 16);
+
+ // Calculate relative luminance
+ const luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
+
+ return luminance;
+ },
+};
diff --git a/js/event_listener.js b/js/event_listener.js
new file mode 100644
index 0000000..e400cba
--- /dev/null
+++ b/js/event_listener.js
@@ -0,0 +1,52 @@
+const EventListener = {
+ init: function () {
+ window.addEventListener('message', this.onMessage);
+ window.addEventListener('notification', this.onNotification);
+ },
+
+ onMessage: function (event) {
+ // Check the message type
+ if (event.data.type === 'focus') {
+ // Process the focus event message
+ const { elementNode, isFocused } = event.data;
+
+ // Perform actions based on the focus event
+ if (isFocused) {
+ console.log(`Element with ID '${elementNode}' is focused`);
+ Keyboard.show();
+ } else {
+ console.log(`Element with ID '${elementNode}' is blurred`);
+ Keyboard.hide();
+ }
+ }
+ },
+
+ appWindow: function (event) {
+ switch (event.channel) {
+ case 'open-app':
+ EventListener.onAppOpen(event);
+ break;
+
+ case 'notification':
+ EventListener.onNotification(event);
+ break;
+
+ default:
+ break;
+ }
+ },
+
+ onAppOpen: function (event) {
+ const { data } = event.args[0];
+ AppWindow.create(data.manifestUrl, { originPos: { x: data.xOrigin, y: data.yOrigin } });
+ },
+
+ onNotification: function (event) {
+ if (event.data.channel === 'notification') {
+ const { data } = event.args[0];
+ NotificationToaster.showNotification(data.title, data.config);
+ }
+ }
+}
+
+EventListener.init();
diff --git a/js/keybinds.js b/js/keybinds.js
new file mode 100644
index 0000000..a9f4bd8
--- /dev/null
+++ b/js/keybinds.js
@@ -0,0 +1,5 @@
+const Keybinds = {
+ init: function () {}
+}
+
+Keybinds.init();
diff --git a/js/keyboard.js b/js/keyboard.js
new file mode 100644
index 0000000..1c33b49
--- /dev/null
+++ b/js/keyboard.js
@@ -0,0 +1,228 @@
+const Keyboard = {
+ screen: document.getElementById("screen"),
+ keyboard: document.getElementById("keyboard"),
+ keyboardSuggestions: document.getElementById("keyboard-auto-correct"),
+ keyboardContent: document.getElementById("keyboard-content"),
+ keyboardLanguages: document.getElementById("keyboard-languages"),
+ keyboardLanguagesButton: document.getElementById("keyboard-languages-button"),
+ toggleButton: document.getElementById("software-keyboard-button"),
+ data: {
+ letters: '',
+ shift: '',
+ symbols: '',
+ },
+ language: 'en-US',
+ inputText: '',
+
+ keySound: new Audio('/resources/sounds/key.wav'),
+ keySpecialSound: new Audio('/resources/sounds/key_special.wav'),
+
+ init: async function () {
+ await fetch(`/keyboard_layouts/${this.language}/letters.txt`)
+ .then(response => response.text())
+ .then(function (data) {
+ Keyboard.data.letters = data;
+ });
+ await fetch(`/keyboard_layouts/${this.language}/shift.txt`)
+ .then(response => response.text())
+ .then(function (data) {
+ Keyboard.data.shift = data;
+ });
+ await fetch(`/keyboard_layouts/${this.language}/symbols.txt`)
+ .then(response => response.text())
+ .then(function (data) {
+ Keyboard.data.symbols = data;
+ });
+
+ this.useLayout(Keyboard.data.letters);
+
+ // Event listeners for input focus and blur
+ this.toggleButton.addEventListener('click', this.toggle.bind(this));
+ },
+
+ useLayout: function (data) {
+ this.keyboardContent.innerHTML = '';
+
+ var lines = data.split(process.platform == 'win32' ? '\r\n' : '\n');
+ lines.forEach(line => {
+ if (!line) {
+ return;
+ }
+
+ var row = document.createElement('div');
+ row.classList.add('row');
+ this.keyboardContent.appendChild(row);
+
+ var keys = line.split(' ');
+ keys.forEach(key => {
+ if (!key) {
+ return;
+ }
+
+ var button = document.createElement('button');
+ button.classList.add('key');
+ button.addEventListener('click', () => {
+ if (document.activeElement) {
+ if (document.activeElement.nodeName === 'INPUT' || document.activeElement.nodeName === 'TEXTAREA') {
+ document.activeElement.focus();
+ } else {
+ var webview = AppWindow.focusedWindow.querySelector('.browser');
+ webview.focus();
+ }
+ }
+ });
+ row.appendChild(button);
+
+ var letter = document.createElement('span');
+ letter.classList.add('letter');
+ button.appendChild(letter);
+
+ var popout = document.createElement('div');
+ popout.classList.add('popout');
+ button.appendChild(popout);
+
+ if (key === '{backspace}') {
+ button.classList.add("backspace");
+ button.dataset.icon = 'dialer-delete';
+ button.addEventListener('click', () => {
+ this.keySpecialSound.play();
+ this.backspace();
+ });
+ } else if (key === '{shift}') {
+ button.classList.add("shift");
+ button.dataset.icon = 'collapse-chevron';
+ button.addEventListener('click', () => {
+ this.keySound.play();
+ this.useLayout(Keyboard.data.shift);
+ });
+ } else if (key === '{unshift}') {
+ button.classList.add("shift");
+ button.classList.add("active");
+ button.dataset.icon = 'expand-chevron';
+ button.addEventListener('click', () => {
+ this.keySound.play();
+ this.useLayout(Keyboard.data.letters);
+ });
+ } else if (/\{symbols\:(.*)\}/.test(key)) {
+ button.classList.add("symbols");
+ var keyString = key.replace('{', '').replace('}', '').split(':')[1];
+ letter.textContent = keyString;
+ button.addEventListener('click', () => {
+ this.keySpecialSound.play();
+ this.useLayout(Keyboard.data.symbols);
+ });
+ } else if (/\{letters\:(.*)\}/.test(key)) {
+ button.classList.add("letters");
+ var keyString = key.replace('{', '').replace('}', '').split(':')[1];
+ letter.textContent = keyString;
+ button.addEventListener('click', () => {
+ this.keySpecialSound.play();
+ this.useLayout(Keyboard.data.letters);
+ });
+ } else if (/\{space\:(.*)\}/.test(key)) {
+ button.classList.add("space");
+ var keyString = key.replace('{', '').replace('}', '').split(':')[1];
+ letter.textContent = keyString;
+ button.addEventListener('click', () => {
+ this.keySpecialSound.play();
+ this.input(' ');
+ });
+ } else if (/\{return\:(.*)\}/.test(key)) {
+ button.classList.add("return");
+ var keyString = key.replace('{', '').replace('}', '').split(':')[1];
+ letter.textContent = keyString;
+ button.addEventListener('click', () => {
+ this.keySpecialSound.play();
+ this.hide();
+ });
+ } else {
+ button.classList.add("has-popout");
+ letter.textContent = key;
+ popout.textContent = key;
+ button.addEventListener('click', () => {
+ this.keySound.play();
+ this.input(key);
+ });
+ }
+ });
+ });
+ },
+
+ input: function (char) {
+ this.inputText += char;
+ // this.suggestWords();
+ if (document.activeElement) {
+ if (document.activeElement.nodeName === 'INPUT' || document.activeElement.nodeName === 'TEXTAREA') {
+ document.activeElement.value += char;
+ } else {
+ var webview = AppWindow.focusedWindow.querySelector('.browser');
+ webview.insertText(char);
+ }
+ }
+ },
+
+ backspace: function () {
+ this.inputText = this.inputText.slice(0, -1);
+ // this.suggestWords();
+ if (document.activeElement) {
+ if (document.activeElement.nodeName === 'INPUT' || document.activeElement.nodeName === 'TEXTAREA') {
+ document.activeElement.value = document.activeElement.value.slice(0, -1);
+ } else {
+ var webview = AppWindow.focusedWindow.querySelector('.browser');
+ webview.executeJavaScript(`
+ if (document.activeElement) {
+ // Append the key to the value of the focused element
+ document.activeElement.value = document.activeElement.value.slice(0, -1);
+ }
+ `);
+ }
+ }
+ },
+
+ show: function () {
+ this.screen.classList.add('keyboard-visible');
+ this.keyboard.classList.add('visible');
+ },
+
+ hide: function () {
+ this.screen.classList.remove('keyboard-visible');
+ this.keyboard.classList.remove('visible');
+ },
+
+ toggle: function () {
+ this.screen.classList.toggle('keyboard-visible');
+ this.keyboard.classList.toggle('visible');
+ },
+
+ suggestWords: function () {
+ var words = this.inputText.slice(' ');
+ var lastWord = words[words.length - 1];
+
+ const inputElement = document.createElement('input');
+ inputElement.setAttribute('type', 'text');
+ inputElement.setAttribute('spellcheck', 'true');
+ inputElement.value = lastWord;
+ document.body.appendChild(inputElement);
+
+ // Trigger the browser's spellcheck
+ inputElement.focus();
+ inputElement.select();
+
+ // Get the suggestions provided by the browser dictionary
+ const suggestions = document.queryCommandValue('suggestions') || [];
+
+ // Remove the temporary input element
+ document.body.removeChild(inputElement);
+
+ // Return the suggestions as similar words
+ this.suggestions = suggestions.slice(0, 3);
+ this.suggestions.forEach(suggestion => {
+ var option = document.createElement('div');
+ option.classList.add('suggestion');
+ option.innerText = suggestion;
+ this.keyboardContent.appendChild(option);
+ });
+ }
+}
+
+Keyboard.init();
diff --git a/js/lockscreen/clock.js b/js/lockscreen/clock.js
new file mode 100644
index 0000000..f71ae2f
--- /dev/null
+++ b/js/lockscreen/clock.js
@@ -0,0 +1,25 @@
+const LockscreenClock = {
+ clockElement: document.getElementById('lockscreen-clock'),
+ is12HourFormat: true, // Set this flag to true for 12-hour format, or false for 24-hour format
+
+ init: function () {
+ this.clockElement.classList.remove('hidden');
+
+ this.update();
+ },
+
+ update: function () {
+ var currentTime = new Date();
+
+ this.clockElement.innerText = currentTime.toLocaleTimeString(navigator.language, {
+ hour12: this.is12HourFormat,
+ hour: 'numeric',
+ minute: '2-digit'
+ });
+
+ clearTimeout(this.timer);
+ this.timer = setTimeout(this.update.bind(this), 1000);
+ }
+};
+
+LockscreenClock.init();
diff --git a/js/lockscreen/date.js b/js/lockscreen/date.js
new file mode 100644
index 0000000..3e679e3
--- /dev/null
+++ b/js/lockscreen/date.js
@@ -0,0 +1,25 @@
+const LockscreenDate = {
+ dateElement: document.getElementById('lockscreen-date'),
+ is12HourFormat: true, // Set this flag to true for 12-hour format, or false for 24-hour format
+
+ init: function () {
+ this.dateElement.classList.remove('hidden');
+
+ this.update();
+ },
+
+ update: function () {
+ var currentTime = new Date();
+
+ this.dateElement.innerText = currentTime.toLocaleDateString(navigator.language, {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+ });
+
+ clearTimeout(this.timer);
+ this.timer = setTimeout(this.update.bind(this), 1000);
+ }
+};
+
+LockscreenDate.init();
diff --git a/js/lockscreen/motion.js b/js/lockscreen/motion.js
new file mode 100644
index 0000000..0ba76e1
--- /dev/null
+++ b/js/lockscreen/motion.js
@@ -0,0 +1,128 @@
+const LockscreenMotion = {
+ motionElement: document.getElementById('lockscreen'),
+ lockscreenIcon: document.getElementById('lockscreen-icon'),
+ startY: 0,
+ currentY: 0,
+ isDragging: false,
+ threshold: 0.75, // Adjust the threshold as desired (0.0 to 1.0)
+
+ lockSound: new Audio('/resources/sounds/lock.wav'),
+ unlockSound: new Audio('/resources/sounds/unlock.opus'),
+
+ init: function() {
+ document.addEventListener('keyup', this.onKeyPress.bind(this));
+
+ this.motionElement.addEventListener('dblclick', this.onDoubleTap.bind(this));
+ this.motionElement.addEventListener('pointerdown', this.onPointerDown.bind(this));
+ document.addEventListener('pointermove', this.onPointerMove.bind(this));
+ document.addEventListener('pointerup', this.onPointerUp.bind(this));
+
+ this.showMotionElement();
+ },
+
+ onKeyPress: function(event) {
+ switch (event.code) {
+ case 'End':
+ this.showMotionElement();
+ this.resetMotionElement();
+ this.isDragging = false;
+ break;
+
+ default:
+ break;
+ }
+ },
+
+ onDoubleTap: function() {
+ this.motionElement.classList.toggle('low-power');
+ },
+
+ onPointerDown: function(event) {
+ event.preventDefault();
+ this.startY = event.clientY;
+ this.currentY = this.startY;
+ this.isDragging = true;
+ },
+
+ onPointerMove: function(event) {
+ event.preventDefault();
+
+ if (this.isDragging) {
+ this.currentY = event.clientY;
+ const offsetY = this.startY - this.currentY;
+ const maxHeight = this.motionElement.offsetHeight;
+ var progress = offsetY / maxHeight;
+
+ progress = Math.max(0, Math.min(1, progress)); // Limit progress between 0 and 1
+
+ this.updateMotionProgress(progress); // Update motion element opacity
+ }
+ },
+
+ onPointerUp: function() {
+ const offsetY = this.startY - this.currentY;
+ const maxHeight = this.motionElement.offsetHeight;
+ const progress = 1 - offsetY / maxHeight;
+
+ this.motionElement.classList.add('transitioning');
+ clearTimeout(this.timer);
+ this.timer = setTimeout(() => {
+ this.motionElement.classList.remove('transitioning');
+ }, 500);
+
+ if (progress >= this.threshold) {
+ this.motionElement.style.setProperty('--motion-progress', 1);
+ this.lockscreenIcon.classList.add('fail-unlock');
+ this.lockscreenIcon.onanimationend = () => {
+ this.lockscreenIcon.classList.remove('fail-unlock');
+ };
+ } else {
+ this.motionElement.style.setProperty('--motion-progress', 0);
+ this.hideMotionElement();
+ }
+
+ this.isDragging = false;
+ },
+
+ updateMotionProgress: function(progress) {
+ const motionProgress = 1 - progress;
+ this.motionElement.style.setProperty('--motion-progress', motionProgress);
+
+ if (motionProgress <= this.threshold) {
+ } else {
+ this.showMotionElement();
+ }
+ },
+
+ hideMotionElement: function() {
+ if (this.isDragging) {
+ this.unlockSound.play();
+ }
+
+ this.motionElement.classList.add('transitioning');
+ this.motionElement.classList.remove('visible');
+ TimeIcon.iconElement.classList.remove('hidden');
+
+ clearTimeout(this.timer);
+ this.timer = setTimeout(() => {
+ this.motionElement.classList.remove('transitioning');
+ }, 500);
+ },
+
+ showMotionElement: function() {
+ this.motionElement.classList.add('visible');
+ this.motionElement.classList.remove('transitioning');
+ TimeIcon.iconElement.classList.add('hidden');
+ },
+
+ resetMotionElement: function() {
+ this.motionElement.classList.add('transitioning');
+ clearTimeout(this.timer);
+ this.timer = setTimeout(() => {
+ this.motionElement.classList.remove('transitioning');
+ }, 500);
+ this.motionElement.style.setProperty('--motion-progress', 1);
+ }
+};
+
+LockscreenMotion.init();
diff --git a/js/network_icon.js b/js/network_icon.js
new file mode 100644
index 0000000..6714fdd
--- /dev/null
+++ b/js/network_icon.js
@@ -0,0 +1,48 @@
+const NetworkIcon = {
+ iconElement: document.getElementById("statusbar-network"),
+
+ init: function () {
+ this.update();
+ },
+
+ update: function () {
+ si.wifiNetworks((networks, error) => {
+ if (error) {
+ console.error(error);
+
+ this.iconElement.classList.add("hidden");
+ } else {
+ this.networks = networks;
+
+ // Find the connected network
+ const connectedNetwork = networks.find(
+ (network) => network.state === "connected"
+ ) || networks[0];
+
+ if (connectedNetwork) {
+ // Retrieve the signal strength
+ const signalStrength = connectedNetwork.quality;
+
+ // Convert signal strength to percentage
+ const signalStrengthPercentage = signalStrength;
+
+ console.log(
+ "Signal Strength:",
+ signalStrengthPercentage.toFixed(2) + "%"
+ );
+
+ this.iconElement.classList.remove("hidden");
+
+ this.iconElement.dataset.icon = `wifi-${Math.round(
+ signalStrengthPercentage / 25
+ )}`;
+ }
+ }
+ });
+
+ clearTimeout(this.timer);
+ this.timer = setTimeout(this.update, 1000);
+ },
+};
+
+NetworkIcon.init();
diff --git a/js/notification_toaster.js b/js/notification_toaster.js
new file mode 100644
index 0000000..e7b7748
--- /dev/null
+++ b/js/notification_toaster.js
@@ -0,0 +1,73 @@
+const NotificationToaster = {
+ notificationElement: document.getElementById('notification-toaster'),
+ titleElement: document.getElementById('notification-title'),
+ detailElement: document.getElementById('notification-detail'),
+ progressElement: document.getElementById('notification-progress'),
+ badgeElement: document.getElementById('notification-badge'),
+ sourceNameElement: document.getElementById('notification-source-name'),
+ iconElement: document.getElementById('notification-icon'),
+ mediaElement: document.getElementById('notification-media'),
+ actionsElement: document.getElementById('notification-actions'),
+
+ showNotification: function (title, options) {
+ const { detail, progress, badgeSrc, sourceName, iconSrc, mediaSrcs, actionButtons } = options;
+
+ this.titleElement.innerText = title;
+ this.detailElement.innerText = detail;
+ this.progressElement.style.width = progress + '%';
+
+ if (badgeSrc) {
+ this.badgeElement.src = badgeSrc;
+ this.badgeElement.style.display = 'block';
+ } else {
+ this.badgeElement.style.display = 'none';
+ }
+
+ this.sourceNameElement.innerText = sourceName;
+
+ if (iconSrc) {
+ this.iconElement.src = iconSrc;
+ this.iconElement.style.display = 'block';
+ } else {
+ this.iconElement.style.display = 'none';
+ }
+
+ if (mediaSrcs && mediaSrcs.length > 0) {
+ this.mediaElement.innerHTML = '';
+ mediaSrcs.forEach(function (src) {
+ const imgElement = document.createElement('img');
+ imgElement.src = src;
+ this.mediaElement.appendChild(imgElement);
+ }, this);
+ this.mediaElement.style.display = 'block';
+ } else {
+ this.mediaElement.style.display = 'none';
+ }
+
+ if (actionButtons && actionButtons.length > 0) {
+ this.actionsElement.innerHTML = '';
+ actionButtons.forEach(function (button) {
+ const buttonElement = document.createElement('button');
+ buttonElement.textContent = button.label;
+ buttonElement.addEventListener('click', button.onclick);
+ if (button.recommend) {
+ buttonElement.classList.add('recommend');
+ }
+ this.actionsElement.appendChild(buttonElement);
+ }, this);
+ this.actionsElement.style.display = 'block';
+ } else {
+ this.actionsElement.style.display = 'none';
+ }
+
+ this.notificationElement.classList.add('visible');
+ clearTimeout(this.timeout);
+ this.timeout = setTimeout(() => {
+ this.notificationElement.classList.remove('visible');
+ }, 3000);
+ },
+
+ hideNotification: function () {
+ this.notificationElement.classList.remove('visible');
+ }
+};
diff --git a/js/screen_capture.js b/js/screen_capture.js
new file mode 100644
index 0000000..3a10c7c
--- /dev/null
+++ b/js/screen_capture.js
@@ -0,0 +1,66 @@
+const { ipcRenderer } = require('electron');
+
+const ScreenCapture = {
+ elementId: 'screen',
+ mediaRecorder: null,
+ recordedChunks: [],
+ isRecording: false,
+
+ toggleButton: document.getElementById('quick-settings-screen-capture'),
+
+ init: function () {
+ this.toggleButton.addEventListener('click', () => {
+ screenCapture.toggleCapture();
+ });
+ },
+
+ startCapture: function () {
+ const element = document.getElementById(this.elementId);
+ const stream = element.captureStream();
+
+ // Create a MediaRecorder instance
+ this.mediaRecorder = new MediaRecorder(stream);
+
+ // Event handler for recording data
+ this.mediaRecorder.ondataavailable = (event) => {
+ if (event.data.size > 0) {
+ this.recordedChunks.push(event.data);
+ }
+ };
+
+ // Event handler for recording stop
+ this.mediaRecorder.onstop = () => {
+ const blob = new Blob(this.recordedChunks, { type: 'video/webm' });
+ const blobUrl = URL.createObjectURL(blob);
+
+ // Send captured video URL to the main process via IPC
+ ipcRenderer.send('captured-video', blobUrl);
+
+ // Reset recordedChunks array
+ this.recordedChunks = [];
+ };
+
+ // Start recording
+ this.mediaRecorder.start();
+ this.isRecording = true;
+ console.log('Capture started');
+ },
+
+ stopCapture: function () {
+ if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
+ this.mediaRecorder.stop();
+ this.isRecording = false;
+ console.log('Capture stopped');
+ }
+ },
+
+ toggleCapture: function () {
+ if (this.isRecording) {
+ this.stopCapture();
+ } else {
+ this.startCapture();
+ }
+ }
+};
+
+ScreenCapture.init();
diff --git a/js/splashscreen.js b/js/splashscreen.js
new file mode 100644
index 0000000..2e9a1bb
--- /dev/null
+++ b/js/splashscreen.js
@@ -0,0 +1,18 @@
+const Splashscreen = {
+ splashElement: document.getElementById('splashscreen'),
+ videoElement: document.getElementById('splashscreen-video'),
+
+ bootAnimationFile: '/resources/videos/splashscreen.mp4',
+
+ init: function () {
+ this.videoElement.src = this.bootAnimationFile;
+ this.videoElement.play();
+ document.addEventListener('DOMContentLoaded', this.onLoad.bind(this));
+ },
+
+ onLoad: function () {
+ this.splashElement.classList.add('hidden');
+ }
+};
+
+Splashscreen.init();
diff --git a/js/time_icon.js b/js/time_icon.js
new file mode 100644
index 0000000..f4a8e2e
--- /dev/null
+++ b/js/time_icon.js
@@ -0,0 +1,25 @@
+const TimeIcon = {
+ iconElement: document.getElementById('statusbar-time'),
+ is12HourFormat: true, // Set this flag to true for 12-hour format, or false for 24-hour format
+
+ init: function () {
+ this.iconElement.classList.remove('hidden');
+
+ this.update();
+ },
+
+ update: function () {
+ var currentTime = new Date();
+
+ this.iconElement.innerText = currentTime.toLocaleTimeString(navigator.language, {
+ hour12: this.is12HourFormat,
+ hour: 'numeric',
+ minute: '2-digit'
+ });
+
+ clearTimeout(this.timer);
+ this.timer = setTimeout(this.update.bind(this), 1000);
+ }
+};
+
+TimeIcon.init();
diff --git a/js/utility_tray_motion.js b/js/utility_tray_motion.js
new file mode 100644
index 0000000..3a9b5be
--- /dev/null
+++ b/js/utility_tray_motion.js
@@ -0,0 +1,96 @@
+const UtilityTrayMotion = {
+ statusbar: document.getElementById('statusbar'),
+ motionElement: document.getElementById('utility-tray-motion'),
+ startY: 0,
+ currentY: 0,
+ isDragging: false,
+ threshold: 0.75, // Adjust the threshold as desired (0.0 to 1.0)
+
+ init: function() {
+ this.statusbar.addEventListener('pointerdown', this.onPointerDown.bind(this));
+ document.addEventListener('pointermove', this.onPointerMove.bind(this));
+ document.addEventListener('pointerup', this.onPointerUp.bind(this));
+ document.addEventListener('pointerleave', this.onPointerUp.bind(this));
+
+ this.motionElement.addEventListener('pointerdown', this.onPointerDown.bind(this));
+ document.addEventListener('pointermove', this.onPointerMove.bind(this));
+ document.addEventListener('pointerup', this.onPointerUp.bind(this));
+ document.addEventListener('pointerleave', this.onPointerUp.bind(this));
+ },
+
+ onPointerDown: function(event) {
+ event.preventDefault();
+ this.startY = event.clientY;
+ this.currentY = this.startY;
+ this.isDragging = true;
+ },
+
+ onPointerMove: function(event) {
+ event.preventDefault();
+
+ if (this.isDragging) {
+ this.currentY = event.clientY;
+ const offsetY = this.startY - this.currentY;
+ const maxHeight = this.motionElement.offsetHeight;
+ var progress = offsetY / maxHeight;
+
+ progress = Math.max(0, Math.min(1, progress)); // Limit progress between 0 and 1
+
+ this.updateMotionProgress(progress); // Update motion element opacity
+ }
+ },
+
+ onPointerUp: function() {
+ const offsetY = this.startY - this.currentY;
+ const maxHeight = this.motionElement.offsetHeight;
+ const progress = 1 - offsetY / maxHeight;
+
+ if (progress >= this.threshold) {
+ this.motionElement.style.setProperty('--motion-progress', 1);
+ } else {
+ this.motionElement.style.setProperty('--motion-progress', 0);
+ this.hideMotionElement();
+ }
+
+ this.isDragging = false;
+ },
+
+ onPointerCancel: function() {
+ this.resetMotionElement();
+ this.isDragging = false;
+ },
+
+ updateMotionProgress: function(progress) {
+ const motionProgress = 1 - progress;
+ this.motionElement.style.setProperty('--motion-progress', motionProgress);
+
+ if (motionProgress <= this.threshold) {
+ this.motionElement.classList.add('fade-out');
+ this.motionElement.classList.remove('fade-in');
+ } else {
+ this.showMotionElement();
+ this.motionElement.classList.add('fade-in');
+ this.motionElement.classList.remove('fade-out');
+ }
+ },
+
+ hideMotionElement: function() {
+ this.motionElement.classList.remove('visible');
+ },
+
+ showMotionElement: function() {
+ this.motionElement.classList.add('visible');
+ },
+
+ resetMotionElement: function() {
+ const offsetY = this.startY - this.currentY;
+ const maxHeight = this.motionElement.offsetHeight;
+ const progress = 1 - offsetY / maxHeight;
+
+ if (progress >= this.threshold) {
+ this.motionElement.style.setProperty('--motion-progress', 1);
+ }
+ }
+};
+
+UtilityTrayMotion.init();
diff --git a/keyboard_layouts/ar/letters.txt b/keyboard_layouts/ar/letters.txt
new file mode 100644
index 0000000..6b009c0
--- /dev/null
+++ b/keyboard_layouts/ar/letters.txt
@@ -0,0 +1,4 @@
+ض ص ث ق ف غ ع ه خ ح ج د
+ش س ي ب ل ا ت ن م ك ط ذ
+ئ ء ؤ ر لا ى ة و ز ظ {backspace}
+{symbols:١٢٣} {space:مسافة} {return:إدخال}
diff --git a/keyboard_layouts/ar/shift.txt b/keyboard_layouts/ar/shift.txt
new file mode 100644
index 0000000..e69de29
diff --git a/keyboard_layouts/ar/symbols.txt b/keyboard_layouts/ar/symbols.txt
new file mode 100644
index 0000000..5d74123
--- /dev/null
+++ b/keyboard_layouts/ar/symbols.txt
@@ -0,0 +1,4 @@
+١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٠
+! @ # $ % ^ & * ( )
+- + _ = [ ] { } {backspace}
+{letters:أب} {space:مسافة} . , {return:إدخال}
diff --git a/keyboard_layouts/en-US/letters.txt b/keyboard_layouts/en-US/letters.txt
new file mode 100644
index 0000000..f0c1259
--- /dev/null
+++ b/keyboard_layouts/en-US/letters.txt
@@ -0,0 +1,4 @@
+q w e r t y u i o p
+a s d f g h j k l
+{shift} z x c v b n m {backspace}
+{symbols:123} {space:space} {return:return}
diff --git a/keyboard_layouts/en-US/shift.txt b/keyboard_layouts/en-US/shift.txt
new file mode 100644
index 0000000..1837d84
--- /dev/null
+++ b/keyboard_layouts/en-US/shift.txt
@@ -0,0 +1,4 @@
+Q W E R T Y U I O P
+A S D F G H J K L
+{unshift} Z X C V B N M {backspace}
+{symbols:123} {space:space} {return:return}
diff --git a/keyboard_layouts/en-US/symbols.txt b/keyboard_layouts/en-US/symbols.txt
new file mode 100644
index 0000000..7d8fe80
--- /dev/null
+++ b/keyboard_layouts/en-US/symbols.txt
@@ -0,0 +1,4 @@
+1 2 3 4 5 6 7 8 9 0
+! @ # $ % ^ & * ( )
+- + _ = [ ] { } {backspace}
+{letters:Abc} {space:space} . , {return:return}
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..d060e1e
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,5 @@
+{
+ "name": "System",
+ "role": "system",
+ "launch_url": "/index.html"
+}
diff --git a/resources/sounds/key.wav b/resources/sounds/key.wav
new file mode 100644
index 0000000..1b4f74f
Binary files /dev/null and b/resources/sounds/key.wav differ
diff --git a/resources/sounds/key_special.wav b/resources/sounds/key_special.wav
new file mode 100644
index 0000000..188b11c
Binary files /dev/null and b/resources/sounds/key_special.wav differ
diff --git a/resources/sounds/unlock.opus b/resources/sounds/unlock.opus
new file mode 100644
index 0000000..e194bbd
Binary files /dev/null and b/resources/sounds/unlock.opus differ
diff --git a/resources/videos/splashscreen.mp4 b/resources/videos/splashscreen.mp4
new file mode 100644
index 0000000..c1aa2a8
Binary files /dev/null and b/resources/videos/splashscreen.mp4 differ
diff --git a/resources/wallpapers/default.png b/resources/wallpapers/default.png
new file mode 100644
index 0000000..104daa3
Binary files /dev/null and b/resources/wallpapers/default.png differ
diff --git a/shared/fonts/JaliArabic-Black.ttf b/shared/fonts/JaliArabic-Black.ttf
new file mode 100644
index 0000000..367c387
Binary files /dev/null and b/shared/fonts/JaliArabic-Black.ttf differ
diff --git a/shared/fonts/JaliArabic-Bold.ttf b/shared/fonts/JaliArabic-Bold.ttf
new file mode 100644
index 0000000..66030a4
Binary files /dev/null and b/shared/fonts/JaliArabic-Bold.ttf differ
diff --git a/shared/fonts/JaliArabic-ExtraBold.ttf b/shared/fonts/JaliArabic-ExtraBold.ttf
new file mode 100644
index 0000000..6654b2c
Binary files /dev/null and b/shared/fonts/JaliArabic-ExtraBold.ttf differ
diff --git a/shared/fonts/JaliArabic-ExtraLight.ttf b/shared/fonts/JaliArabic-ExtraLight.ttf
new file mode 100644
index 0000000..0474858
Binary files /dev/null and b/shared/fonts/JaliArabic-ExtraLight.ttf differ
diff --git a/shared/fonts/JaliArabic-Light.ttf b/shared/fonts/JaliArabic-Light.ttf
new file mode 100644
index 0000000..c992f78
Binary files /dev/null and b/shared/fonts/JaliArabic-Light.ttf differ
diff --git a/shared/fonts/JaliArabic-Medium.ttf b/shared/fonts/JaliArabic-Medium.ttf
new file mode 100644
index 0000000..4271278
Binary files /dev/null and b/shared/fonts/JaliArabic-Medium.ttf differ
diff --git a/shared/fonts/JaliArabic-Regular.ttf b/shared/fonts/JaliArabic-Regular.ttf
new file mode 100644
index 0000000..434ba89
Binary files /dev/null and b/shared/fonts/JaliArabic-Regular.ttf differ
diff --git a/shared/fonts/JaliArabic-SemiBold.ttf b/shared/fonts/JaliArabic-SemiBold.ttf
new file mode 100644
index 0000000..4629b0a
Binary files /dev/null and b/shared/fonts/JaliArabic-SemiBold.ttf differ
diff --git a/shared/js/buttons.js b/shared/js/buttons.js
new file mode 100644
index 0000000..4054f8f
--- /dev/null
+++ b/shared/js/buttons.js
@@ -0,0 +1,39 @@
+// Add click event listener to elements with .ripple-button class
+const rippleButtons = document.querySelectorAll(".ripple-button");
+rippleButtons.forEach((button) => {
+ button.addEventListener("click", createRipple);
+});
+
+// Create ripple effect on click
+function createRipple(event) {
+ const button = event.currentTarget;
+
+ // Create ripple element
+ const ripple = document.createElement("span");
+ ripple.classList.add("ripple");
+
+ // Calculate ripple size based on button dimensions
+ const buttonRect = button.getBoundingClientRect();
+ const size = Math.max(buttonRect.width, buttonRect.height) * 2;
+
+ // Position ripple element
+ const posX = event.clientX - buttonRect.left - size / 2;
+ const posY = event.clientY - buttonRect.top - size / 2;
+ ripple.style.cssText = `
+ width: ${size}px;
+ height: ${size}px;
+ top: ${posY}px;
+ left: ${posX}px;
+ `;
+
+ // Append ripple element to the button
+ button.appendChild(ripple);
+
+ // Add animation class to enable the ripple effect
+ ripple.classList.add("animate");
+
+ // Remove the ripple element after the animation is complete
+ setTimeout(() => {
+ ripple.remove();
+ }, 1000);
+}
diff --git a/shared/js/panels.js b/shared/js/panels.js
new file mode 100644
index 0000000..19ef3b2
--- /dev/null
+++ b/shared/js/panels.js
@@ -0,0 +1,35 @@
+// Panel object
+var Panel = {
+ panels: null,
+
+ // Initialize the panel object
+ init() {
+ this.panels = document.querySelectorAll('.panel');
+ this.bindScrollEvents();
+ },
+
+ // Bind scroll events to each panel
+ bindScrollEvents() {
+ this.panels.forEach(panel => {
+ const content = panel.querySelector('.content');
+
+ content.addEventListener('scroll', () => {
+ const scrollPosition = content.scrollTop;
+ var progress = scrollPosition / 80;
+ if (progress >= 1) {
+ progress = 1;
+ }
+
+ this.setProgress(panel, progress);
+ });
+ });
+ },
+
+ // Set progress value on the header bar
+ setProgress(panel, progress) {
+ panel.style.setProperty('--progress', progress);
+ }
+};
+
+// Initialize the Panel object
+Panel.init();
diff --git a/shared/js/webview-preload.js b/shared/js/webview-preload.js
new file mode 100644
index 0000000..5e73490
--- /dev/null
+++ b/shared/js/webview-preload.js
@@ -0,0 +1,26 @@
+const { ipcRenderer } = require('electron');
+
+document.addEventListener('focus', event => {
+ if (event.target.nodeName === 'INPUT') {
+ window.parent.postMessage({ type: 'focus', element: event.target.id, isFocused: true }, '*');
+ }
+}, true);
+
+document.addEventListener('blur', event => {
+ if (event.target.nodeName === 'INPUT') {
+ window.parent.postMessage({ type: 'focus', element: event.target.id, isFocused: false }, '*');
+ }
+}, true);
+
+// Override the Notification constructor
+window.Notification = class Notification {
+ constructor(title, options) {
+ // Forward the notification data to the parent renderer process
+ ipcRenderer.sendToHost('notification', {
+ data: {
+ title,
+ options
+ }
+ });
+ }
+};
diff --git a/shared/js/webview.js b/shared/js/webview.js
new file mode 100644
index 0000000..e69de29
diff --git a/shared/manifest.json b/shared/manifest.json
new file mode 100644
index 0000000..63f4964
--- /dev/null
+++ b/shared/manifest.json
@@ -0,0 +1,5 @@
+{
+ "name": "Shared",
+ "role": "system",
+ "launch_url": "/index.html"
+}
diff --git a/shared/style/buttons.css b/shared/style/buttons.css
new file mode 100644
index 0000000..e03126b
--- /dev/null
+++ b/shared/style/buttons.css
@@ -0,0 +1,34 @@
+.ripple-button {
+ position: relative;
+ overflow: hidden;
+ display: inline-block;
+ cursor: pointer;
+}
+
+.ripple {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 0;
+ height: 0;
+ background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0.2), transparent 75%);
+ border-radius: 50%;
+ pointer-events: none;
+}
+
+.ripple.animate {
+ animation: rippleEffect 0.75s ease forwards;
+}
+
+@keyframes rippleEffect {
+ 0% {
+ opacity: 1;
+ transform: scale(0);
+ }
+ 100% {
+ opacity: 0;
+ transform: scale(1);
+ }
+}
diff --git a/shared/style/fonts.css b/shared/style/fonts.css
new file mode 100644
index 0000000..5f61b22
--- /dev/null
+++ b/shared/style/fonts.css
@@ -0,0 +1,51 @@
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-ExtraLight.ttf);
+ font-weight: 200;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Light.ttf);
+ font-weight: 300;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Regular.ttf);
+ font-weight: 400;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Medium.ttf);
+ font-weight: 500;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-SemiBold.ttf);
+ font-weight: 600;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Bold.ttf);
+ font-weight: 700;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-ExtraBold.ttf);
+ font-weight: 800;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Black.ttf);
+ font-weight: 900;
+}
+
+*, ::placeholder {
+ font-family: 'Jali Arabic';
+}
diff --git a/shared/style/headerbars.css b/shared/style/headerbars.css
new file mode 100644
index 0000000..9c2710c
--- /dev/null
+++ b/shared/style/headerbars.css
@@ -0,0 +1,79 @@
+.headerbar {
+ width: 100%;
+ height: calc(var(--statusbar-height) + 5rem + (4rem * (1 - var(--progress, 0))));
+ background-color: rgba(var(--headerbar-r), var(--headerbar-g), var(--headerbar-b), calc(var(--progress, 0) * 0.75));
+ display: flex;
+ padding: var(--statusbar-height) 1rem 0;
+ box-sizing: border-box;
+ z-index: 10;
+ flex-shrink: 0;
+ backdrop-filter: blur(20px) saturate(calc(100% + (80% * var(--progress, 0))));
+}
+
+.headerbar .safezone {
+ width: 100%;
+ max-width: 74.5rem;
+ margin: 0 auto;
+ display: flex;
+}
+
+.headerbar h1 {
+ flex-grow: 1;
+ margin: 0;
+ padding: 0 1rem;
+ box-sizing: border-box;
+ height: calc(5rem - (1rem * (1 - var(--progress, 0))));
+ line-height: calc(5rem - (1rem * (1 - var(--progress, 0))));
+ display: inline-block;
+ color: var(--text-color);
+ font-weight: normal;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ transform: translateY(calc(4.5rem * (1 - var(--progress, 0))));
+ width: 100%;
+ font-size: calc(2rem + (0.8rem * (1 - var(--progress, 0))));
+}
+
+.headerbar a + h1 {
+ transform: translate(calc(-4rem * (1 - var(--progress, 0))), calc(4.5rem * (1 - var(--progress, 0))));
+}
+
+.headerbar a {
+ width: 4rem;
+ height: 4rem;
+ text-decoration: none;
+ line-height: 4rem;
+ border-radius: 50%;
+ display: inline-block;
+ color: var(--text-color);
+ flex-shrink: 0;
+ margin: 0.5rem 0;
+ text-align: center;
+ padding: 0 1rem;
+ box-sizing: border-box;
+}
+
+.headerbar a:hover {
+ background-color: var(--item-hover);
+}
+
+.headerbar a:active {
+ background-color: var(--item-active);
+}
+
+.headerbar a[data-icon]::before {
+ width: 2rem;
+ height: 4rem;
+ line-height: 4rem;
+ font-size: 2rem;
+}
+
+.headerbar menu[role="toolbar"] {
+ display: inline-flex;
+ height: 5rem;
+ flex-shrink: 0;
+ margin: 0;
+ padding: 0;
+ /* transform: translate(0, calc(50% * (1 - var(--progress, 0)))); */
+}
diff --git a/shared/style/icons/fonts/openorchid-icons.eot b/shared/style/icons/fonts/openorchid-icons.eot
new file mode 100644
index 0000000..92675a1
Binary files /dev/null and b/shared/style/icons/fonts/openorchid-icons.eot differ
diff --git a/shared/style/icons/fonts/openorchid-icons.svg b/shared/style/icons/fonts/openorchid-icons.svg
new file mode 100644
index 0000000..5a9e7a0
--- /dev/null
+++ b/shared/style/icons/fonts/openorchid-icons.svg
@@ -0,0 +1,959 @@
+
+
+
\ No newline at end of file
diff --git a/shared/style/icons/fonts/openorchid-icons.ttf b/shared/style/icons/fonts/openorchid-icons.ttf
new file mode 100644
index 0000000..666be18
Binary files /dev/null and b/shared/style/icons/fonts/openorchid-icons.ttf differ
diff --git a/shared/style/icons/fonts/openorchid-icons.woff b/shared/style/icons/fonts/openorchid-icons.woff
new file mode 100644
index 0000000..c516071
Binary files /dev/null and b/shared/style/icons/fonts/openorchid-icons.woff differ
diff --git a/shared/style/icons/icons.css b/shared/style/icons/icons.css
new file mode 100644
index 0000000..a369788
--- /dev/null
+++ b/shared/style/icons/icons.css
@@ -0,0 +1,1454 @@
+/* Generated by grunt-webfont */
+/* Based on https://github.com/endtwist/fontcustom/blob/master/lib/fontcustom/templates/fontcustom.css */
+
+
+@font-face {
+ font-family: "openorchid-icons";
+ src: url('fonts/openorchid-icons.eot');
+ src: url('fonts/openorchid-icons.eot') format('embedded-opentype'),
+ url('fonts/openorchid-icons.ttf') format('truetype'),
+ url('fonts/openorchid-icons.woff') format('woff'),
+ url('fonts/openorchid-icons.svg#openorchid-icons') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ font-display: block;
+}
+
+
+[data-icon]:before,
+.ligature-icons {
+ font-family: "openorchid-icons";
+ content: attr(data-icon);
+ display: inline-block;
+ font-weight: 500;
+ font-style: normal;
+ text-decoration: inherit;
+ text-transform: none;
+ text-rendering: optimizeLegibility;
+ font-size: 30px;
+ -webkit-font-smoothing: antialiased;
+}
+
+
+.icon-accessibility:before {
+ content: "\e900";
+}
+.icon-achievement:before {
+ content: "\e901";
+}
+.icon-activecall-bluetooth:before {
+ content: "\e902";
+}
+.icon-activecall-hangup:before {
+ content: "\e903";
+}
+.icon-activecall-hold:before {
+ content: "\e904";
+}
+.icon-activecall-mergecalls:before {
+ content: "\e905";
+}
+.icon-activecall-mute:before {
+ content: "\e906";
+}
+.icon-activecall-pickup:before {
+ content: "\e907";
+}
+.icon-activecall-sms:before {
+ content: "\e908";
+}
+.icon-activecall-speaker:before {
+ content: "\e909";
+}
+.icon-activecall-switchlines:before {
+ content: "\e90a";
+}
+.icon-activecall-voicemail:before {
+ content: "\e90b";
+}
+.icon-add:before {
+ content: "\e90c";
+}
+.icon-addons:before {
+ content: "\e90d";
+}
+.icon-airplane:before {
+ content: "\e90e";
+}
+.icon-alarm-clock:before {
+ content: "\e90f";
+}
+.icon-alarmstop:before {
+ content: "\e910";
+}
+.icon-album:before {
+ content: "\e911";
+}
+.icon-all-day:before {
+ content: "\e912";
+}
+.icon-apps:before {
+ content: "\e913";
+}
+.icon-artist:before {
+ content: "\e914";
+}
+.icon-attachments:before {
+ content: "\e915";
+}
+.icon-audio:before {
+ content: "\e916";
+}
+.icon-auth:before {
+ content: "\e917";
+}
+.icon-auto-enhance-spark:before {
+ content: "\e918";
+}
+.icon-back:before {
+ content: "\e91a";
+}
+.icon-back-light:before {
+ content: "\e91b";
+}
+.icon-battery:before {
+ content: "\e91c";
+}
+.icon-battery-0:before {
+ content: "\e91d";
+}
+.icon-battery-10:before {
+ content: "\e91e";
+}
+.icon-battery-100:before {
+ content: "\e927";
+}
+.icon-battery-20:before {
+ content: "\e91f";
+}
+.icon-battery-30:before {
+ content: "\e920";
+}
+.icon-battery-40:before {
+ content: "\e921";
+}
+.icon-battery-50:before {
+ content: "\e922";
+}
+.icon-battery-60:before {
+ content: "\e923";
+}
+.icon-battery-70:before {
+ content: "\e924";
+}
+.icon-battery-80:before {
+ content: "\e925";
+}
+.icon-battery-90:before {
+ content: "\e926";
+}
+.icon-battery-charging:before {
+ content: "\e928";
+}
+.icon-battery-charging-0:before {
+ content: "\e929";
+}
+.icon-battery-charging-10:before {
+ content: "\e92a";
+}
+.icon-battery-charging-100:before {
+ content: "\e933";
+}
+.icon-battery-charging-20:before {
+ content: "\e92b";
+}
+.icon-battery-charging-30:before {
+ content: "\e92c";
+}
+.icon-battery-charging-40:before {
+ content: "\e92d";
+}
+.icon-battery-charging-50:before {
+ content: "\e92e";
+}
+.icon-battery-charging-60:before {
+ content: "\e92f";
+}
+.icon-battery-charging-70:before {
+ content: "\e930";
+}
+.icon-battery-charging-80:before {
+ content: "\e931";
+}
+.icon-battery-charging-90:before {
+ content: "\e932";
+}
+.icon-bell:before {
+ content: "\e934";
+}
+.icon-bluetooth:before {
+ content: "\e935";
+}
+.icon-bookmark:before {
+ content: "\e936";
+}
+.icon-bookmarked:before {
+ content: "\e937";
+}
+.icon-brightness:before {
+ content: "\e938";
+}
+.icon-browser-back:before {
+ content: "\e939";
+}
+.icon-browser-closecancel:before {
+ content: "\e93a";
+}
+.icon-browser-crashedtab:before {
+ content: "\e93b";
+}
+.icon-browser-forward:before {
+ content: "\e93c";
+}
+.icon-browser-home:before {
+ content: "\e93d";
+}
+.icon-browser-library:before {
+ content: "\e93e";
+}
+.icon-browser-moretabs:before {
+ content: "\e93f";
+}
+.icon-browser-nofavicon:before {
+ content: "\e940";
+}
+.icon-browser-pictureinpicture:before {
+ content: "\e941";
+}
+.icon-browser-readermode:before {
+ content: "\e942";
+}
+.icon-browser-reload:before {
+ content: "\e943";
+}
+.icon-browser-search:before {
+ content: "\e944";
+}
+.icon-browser-secure:before {
+ content: "\e945";
+}
+.icon-browser-secureunverified:before {
+ content: "\e946";
+}
+.icon-browser-sidetabs:before {
+ content: "\e947";
+}
+.icon-browser-tabpreviews:before {
+ content: "\e948";
+}
+.icon-browsing:before {
+ content: "\e949";
+}
+.icon-bug:before {
+ content: "\e94a";
+}
+.icon-calendar-alarm:before {
+ content: "\e94b";
+}
+.icon-calendar-allday:before {
+ content: "\e94c";
+}
+.icon-calendar-bullet:before {
+ content: "\e94d";
+}
+.icon-calendar-dot:before {
+ content: "\e94e";
+}
+.icon-calendar-eventalarm:before {
+ content: "\e94f";
+}
+.icon-calendar-today:before {
+ content: "\e950";
+}
+.icon-call:before {
+ content: "\e951";
+}
+.icon-call-incoming:before {
+ content: "\e952";
+}
+.icon-call-outgoing:before {
+ content: "\e95c";
+}
+.icon-call-ringing:before {
+ content: "\e95d";
+}
+.icon-calllog-checkboxoff:before {
+ content: "\e953";
+}
+.icon-calllog-checkboxon-box:before {
+ content: "\e954";
+}
+.icon-calllog-checkboxon-checkmark:before {
+ content: "\e955";
+}
+.icon-calllog-expand:before {
+ content: "\e956";
+}
+.icon-calllog-incomingcall:before {
+ content: "\e957";
+}
+.icon-calllog-incomingsms:before {
+ content: "\e958";
+}
+.icon-calllog-missedcall:before {
+ content: "\e959";
+}
+.icon-calllog-outgoingcall:before {
+ content: "\e95a";
+}
+.icon-calllog-outgoingsms:before {
+ content: "\e95b";
+}
+.icon-camera:before {
+ content: "\e95e";
+}
+.icon-camera-cameraorientation:before {
+ content: "\e95f";
+}
+.icon-camera-flashauto:before {
+ content: "\e960";
+}
+.icon-camera-flashoff:before {
+ content: "\e961";
+}
+.icon-camera-flashon:before {
+ content: "\e962";
+}
+.icon-camera-videorecorder:before {
+ content: "\e963";
+}
+.icon-change-wallpaper:before {
+ content: "\e964";
+}
+.icon-checked:before {
+ content: "\e965";
+}
+.icon-clear-all:before {
+ content: "\e966";
+}
+.icon-clearcancel-circle:before {
+ content: "\e967";
+}
+.icon-clearcancel-cross:before {
+ content: "\e968";
+}
+.icon-close:before {
+ content: "\e969";
+}
+.icon-closecancel:before {
+ content: "\e96a";
+}
+.icon-collapse-chevron:before {
+ content: "\e96b";
+}
+.icon-compose:before {
+ content: "\e96c";
+}
+.icon-contact-add:before {
+ content: "\e96d";
+}
+.icon-contact-addfavorite:before {
+ content: "\e96e";
+}
+.icon-contact-addimage:before {
+ content: "\e96f";
+}
+.icon-contact-checkmark:before {
+ content: "\e970";
+}
+.icon-contact-delete-circle:before {
+ content: "\e971";
+}
+.icon-contact-delete-minus:before {
+ content: "\e972";
+}
+.icon-contact-detailfacebook-f:before {
+ content: "\e973";
+}
+.icon-contact-detailfacebook-square:before {
+ content: "\e974";
+}
+.icon-contact-email:before {
+ content: "\e975";
+}
+.icon-contact-favorite:before {
+ content: "\e976";
+}
+.icon-contact-favorited:before {
+ content: "\e977";
+}
+.icon-contact-favoritedcontact:before {
+ content: "\e978";
+}
+.icon-contact-find:before {
+ content: "\e979";
+}
+.icon-contact-link:before {
+ content: "\e97a";
+}
+.icon-contact-location:before {
+ content: "\e97b";
+}
+.icon-contact-phone:before {
+ content: "\e97c";
+}
+.icon-contact-sms:before {
+ content: "\e97e";
+}
+.icon-contact-twitter:before {
+ content: "\e97f";
+}
+.icon-contact-undo-roundarrow:before {
+ content: "\e981";
+}
+.icon-contacts:before {
+ content: "\e97d";
+}
+.icon-copy:before {
+ content: "\e982";
+}
+.icon-costcontrol-topup:before {
+ content: "\e983";
+}
+.icon-costcontrol-topuppay:before {
+ content: "\e984";
+}
+.icon-costcontrol-topupwithcode:before {
+ content: "\e985";
+}
+.icon-costcontrol-updatebalance:before {
+ content: "\e986";
+}
+.icon-crop:before {
+ content: "\e987";
+}
+.icon-cut:before {
+ content: "\e988";
+}
+.icon-data:before {
+ content: "\e989";
+}
+.icon-database:before {
+ content: "\e98a";
+}
+.icon-delete:before {
+ content: "\e98b";
+}
+.icon-desktop:before {
+ content: "\e98c";
+}
+.icon-developer:before {
+ content: "\e98d";
+}
+.icon-dialer-contacts:before {
+ content: "\e98e";
+}
+.icon-dialer-delete:before {
+ content: "\e98f";
+}
+.icon-dialer-dialpad:before {
+ content: "\e990";
+}
+.icon-dialer-recentcalls:before {
+ content: "\e991";
+}
+.icon-dialpad:before {
+ content: "\e992";
+}
+.icon-discord:before {
+ content: "\e993";
+}
+.icon-dislike:before {
+ content: "\e994";
+}
+.icon-disliked:before {
+ content: "\e995";
+}
+.icon-dismisskeyboard:before {
+ content: "\e996";
+}
+.icon-display:before {
+ content: "\e997";
+}
+.icon-do-not-track:before {
+ content: "\e998";
+}
+.icon-download:before {
+ content: "\e999";
+}
+.icon-download-circle:before {
+ content: "\e99a";
+}
+.icon-edit:before {
+ content: "\e99b";
+}
+.icon-edit-image:before {
+ content: "\e99d";
+}
+.icon-editcontact:before {
+ content: "\e99c";
+}
+.icon-eject:before {
+ content: "\e99e";
+}
+.icon-email:before {
+ content: "\e99f";
+}
+.icon-email-addrecipient-circle:before {
+ content: "\e9a0";
+}
+.icon-email-addrecipient-plus:before {
+ content: "\e9a1";
+}
+.icon-email-attachment:before {
+ content: "\e9a2";
+}
+.icon-email-downloadattachment:before {
+ content: "\e9a3";
+}
+.icon-email-flag:before {
+ content: "\e9a4";
+}
+.icon-email-forward:before {
+ content: "\e9a5";
+}
+.icon-email-markread:before {
+ content: "\e9a6";
+}
+.icon-email-markunread:before {
+ content: "\e9a7";
+}
+.icon-email-move:before {
+ content: "\e9a8";
+}
+.icon-email-removeattachment-circle:before {
+ content: "\e9a9";
+}
+.icon-email-removeattachment-cross:before {
+ content: "\e9aa";
+}
+.icon-email-reply:before {
+ content: "\e9ab";
+}
+.icon-email-replyall:before {
+ content: "\e9ac";
+}
+.icon-email-send:before {
+ content: "\e9ad";
+}
+.icon-emailsmscalilog-editlist:before {
+ content: "\e9ae";
+}
+.icon-emojis:before {
+ content: "\e9af";
+}
+.icon-eraser:before {
+ content: "\e9b0";
+}
+.icon-expand:before {
+ content: "\e9b1";
+}
+.icon-expand-chevron:before {
+ content: "\e9b2";
+}
+.icon-export:before {
+ content: "\e9b3";
+}
+.icon-face-recognition:before {
+ content: "\e9b5";
+}
+.icon-face-recognition-fail:before {
+ content: "\e9b6";
+}
+.icon-facebook:before {
+ content: "\e9b4";
+}
+.icon-favorites:before {
+ content: "\e9b7";
+}
+.icon-feedback:before {
+ content: "\e9b8";
+}
+.icon-file:before {
+ content: "\e9b9";
+}
+.icon-find:before {
+ content: "\e9ba";
+}
+.icon-fingerprint:before {
+ content: "\e9bb";
+}
+.icon-firefox:before {
+ content: "\e9bc";
+}
+.icon-flag:before {
+ content: "\e9bd";
+}
+.icon-flashlight:before {
+ content: "\e9be";
+}
+.icon-fm-favouritedstation:before {
+ content: "\e9bf";
+}
+.icon-fm-sound:before {
+ content: "\e9c0";
+}
+.icon-folder:before {
+ content: "\e9c1";
+}
+.icon-forbidden:before {
+ content: "\e9c2";
+}
+.icon-forward:before {
+ content: "\e9c3";
+}
+.icon-forward-light:before {
+ content: "\e9c4";
+}
+.icon-ftu-importgmail:before {
+ content: "\e9c5";
+}
+.icon-ftu-importoutlook:before {
+ content: "\e9c6";
+}
+.icon-ftu-importsdcard:before {
+ content: "\e9c7";
+}
+.icon-ftu-importsim:before {
+ content: "\e9c8";
+}
+.icon-fullscreen:before {
+ content: "\e9c9";
+}
+.icon-fullscreen-exit:before {
+ content: "\e9ca";
+}
+.icon-gallery-autoenhancespark:before {
+ content: "\e9cb";
+}
+.icon-gallery-crop:before {
+ content: "\e9cd";
+}
+.icon-gallery-crop-photo:before {
+ content: "\e9d2";
+}
+.icon-gallery-crop1x1-mark:before {
+ content: "\e9ce";
+}
+.icon-gallery-crop2x3-mark:before {
+ content: "\e9cf";
+}
+.icon-gallery-crop3x2-mark:before {
+ content: "\e9d0";
+}
+.icon-gallery-cropfree-mark:before {
+ content: "\e9d1";
+}
+.icon-gallery-exposure:before {
+ content: "\e9d3";
+}
+.icon-gallery-filterscircleopacity100:before {
+ content: "\e9d6";
+}
+.icon-gallery-filterscircleopacity35:before {
+ content: "\e9d4";
+}
+.icon-gallery-filterscircleopacity50:before {
+ content: "\e9d5";
+}
+.icon-gallery-rotate:before {
+ content: "\e9d7";
+}
+.icon-game:before {
+ content: "\e9d8";
+}
+.icon-gerneral-unlock:before {
+ content: "\e9d9";
+}
+.icon-gesture:before {
+ content: "\e9da";
+}
+.icon-gmail:before {
+ content: "\e9db";
+}
+.icon-google:before {
+ content: "\e9dc";
+}
+.icon-grid:before {
+ content: "\e9dd";
+}
+.icon-heart:before {
+ content: "\e9de";
+}
+.icon-help:before {
+ content: "\e9df";
+}
+.icon-history:before {
+ content: "\e9e0";
+}
+.icon-home:before {
+ content: "\e9e1";
+}
+.icon-homescreen:before {
+ content: "\e9e2";
+}
+.icon-homescreendelete-circle:before {
+ content: "\e9e3";
+}
+.icon-homescreendelete-cross:before {
+ content: "\e9e4";
+}
+.icon-info:before {
+ content: "\e9e5";
+}
+.icon-instagram:before {
+ content: "\e9e6";
+}
+.icon-iris-scanner:before {
+ content: "\e9e7";
+}
+.icon-iris-scanner-fail:before {
+ content: "\e9e8";
+}
+.icon-iris-scanner-success:before {
+ content: "\e9e9";
+}
+.icon-keyboard:before {
+ content: "\e9ea";
+}
+.icon-keyboard-circle:before {
+ content: "\e9eb";
+}
+.icon-languages:before {
+ content: "\e9ec";
+}
+.icon-left:before {
+ content: "\e9ed";
+}
+.icon-left-light:before {
+ content: "\e9ee";
+}
+.icon-library:before {
+ content: "\e9ef";
+}
+.icon-like:before {
+ content: "\e9f0";
+}
+.icon-liked:before {
+ content: "\e9f1";
+}
+.icon-link:before {
+ content: "\e9f2";
+}
+.icon-linkedin:before {
+ content: "\e9f3";
+}
+.icon-location:before {
+ content: "\e9f4";
+}
+.icon-lock:before {
+ content: "\e9f5";
+}
+.icon-logout:before {
+ content: "\e9f6";
+}
+.icon-media-camera:before {
+ content: "\e9f7";
+}
+.icon-media-info:before {
+ content: "\e9f8";
+}
+.icon-media-pause:before {
+ content: "\e9f9";
+}
+.icon-media-play:before {
+ content: "\e9fa";
+}
+.icon-media-playcircle:before {
+ content: "\e9fb";
+}
+.icon-media-repeatinfinite:before {
+ content: "\e9fc";
+}
+.icon-media-repeatonce:before {
+ content: "\e9fd";
+}
+.icon-media-seekbackward:before {
+ content: "\e9fe";
+}
+.icon-media-seekforward:before {
+ content: "\e9ff";
+}
+.icon-media-shuffle:before {
+ content: "\ea00";
+}
+.icon-media-skipbackward:before {
+ content: "\ea01";
+}
+.icon-media-skipforward:before {
+ content: "\ea02";
+}
+.icon-media-songs:before {
+ content: "\ea03";
+}
+.icon-media-stop:before {
+ content: "\ea04";
+}
+.icon-media-storage:before {
+ content: "\ea05";
+}
+.icon-menu:before {
+ content: "\ea06";
+}
+.icon-messages:before {
+ content: "\ea07";
+}
+.icon-mic:before {
+ content: "\ea08";
+}
+.icon-miscellaneous-editimage:before {
+ content: "\ea09";
+}
+.icon-miscellaneous-select:before {
+ content: "\ea0a";
+}
+.icon-miscellaneous-undo:before {
+ content: "\ea0b";
+}
+.icon-moderator:before {
+ content: "\ea0c";
+}
+.icon-moon:before {
+ content: "\ea0d";
+}
+.icon-more:before {
+ content: "\ea0e";
+}
+.icon-music-album:before {
+ content: "\ea0f";
+}
+.icon-music-artist:before {
+ content: "\ea10";
+}
+.icon-music-gridview:before {
+ content: "\ea11";
+}
+.icon-music-playlist:before {
+ content: "\ea12";
+}
+.icon-newadd:before {
+ content: "\ea13";
+}
+.icon-nfc:before {
+ content: "\ea14";
+}
+.icon-notification-bluetooth:before {
+ content: "\ea15";
+}
+.icon-notification-bluetoothtransfer:before {
+ content: "\ea16";
+}
+.icon-notification-cameramic:before {
+ content: "\ea17";
+}
+.icon-notification-cameraon:before {
+ content: "\ea18";
+}
+.icon-notification-circle:before {
+ content: "\ea19";
+}
+.icon-notification-download:before {
+ content: "\ea1a";
+}
+.icon-notification-downloadfailed-exclamation:before {
+ content: "\ea1b";
+}
+.icon-notification-facebook:before {
+ content: "\ea1c";
+}
+.icon-notification-importingfrommemorycard:before {
+ content: "\ea1d";
+}
+.icon-notification-lowstorage:before {
+ content: "\ea1e";
+}
+.icon-notification-mic:before {
+ content: "\ea1f";
+}
+.icon-notifications:before {
+ content: "\ea20";
+}
+.icon-options:before {
+ content: "\ea21";
+}
+.icon-outlook:before {
+ content: "\ea22";
+}
+.icon-paintbrush:before {
+ content: "\ea23";
+}
+.icon-paintbucket:before {
+ content: "\ea24";
+}
+.icon-paste:before {
+ content: "\ea25";
+}
+.icon-pause:before {
+ content: "\ea26";
+}
+.icon-permissions:before {
+ content: "\ea27";
+}
+.icon-phone:before {
+ content: "\ea28";
+}
+.icon-picture-in-picture:before {
+ content: "\ea29";
+}
+.icon-pin:before {
+ content: "\ea2a";
+}
+.icon-play:before {
+ content: "\ea2b";
+}
+.icon-play-circle:before {
+ content: "\ea2c";
+}
+.icon-playlist:before {
+ content: "\ea2d";
+}
+.icon-power:before {
+ content: "\ea2e";
+}
+.icon-qr:before {
+ content: "\ea2f";
+}
+.icon-qr-scan:before {
+ content: "\ea30";
+}
+.icon-quote:before {
+ content: "\ea31";
+}
+.icon-reader-mode:before {
+ content: "\ea32";
+}
+.icon-recent-calls:before {
+ content: "\ea33";
+}
+.icon-redo:before {
+ content: "\ea34";
+}
+.icon-reload:before {
+ content: "\ea35";
+}
+.icon-repeat:before {
+ content: "\ea36";
+}
+.icon-repeat-once:before {
+ content: "\ea37";
+}
+.icon-right:before {
+ content: "\ea38";
+}
+.icon-right-light:before {
+ content: "\ea39";
+}
+.icon-save:before {
+ content: "\ea3a";
+}
+.icon-sdcard:before {
+ content: "\ea3b";
+}
+.icon-search:before {
+ content: "\ea3c";
+}
+.icon-select:before {
+ content: "\ea3d";
+}
+.icon-selectall:before {
+ content: "\ea3e";
+}
+.icon-send:before {
+ content: "\ea3f";
+}
+.icon-settings:before {
+ content: "\ea40";
+}
+.icon-settings-aboutphone:before {
+ content: "\ea41";
+}
+.icon-settings-accessibility:before {
+ content: "\ea42";
+}
+.icon-settings-airplane:before {
+ content: "\ea43";
+}
+.icon-settings-app-permissions:before {
+ content: "\ea44";
+}
+.icon-settings-apps:before {
+ content: "\ea45";
+}
+.icon-settings-appstorage:before {
+ content: "\ea46";
+}
+.icon-settings-battery:before {
+ content: "\ea47";
+}
+.icon-settings-bluetooth:before {
+ content: "\ea48";
+}
+.icon-settings-brightness:before {
+ content: "\ea49";
+}
+.icon-settings-brightness-lower:before {
+ content: "\ea4a";
+}
+.icon-settings-call:before {
+ content: "\ea4b";
+}
+.icon-settings-camera-permissions:before {
+ content: "\ea4c";
+}
+.icon-settings-changewallpapericon:before {
+ content: "\ea4e";
+}
+.icon-settings-contacts-permissions:before {
+ content: "\ea4f";
+}
+.icon-settings-developer:before {
+ content: "\ea50";
+}
+.icon-settings-deviceinfo:before {
+ content: "\ea51";
+}
+.icon-settings-devicestorage-permissions:before {
+ content: "\ea52";
+}
+.icon-settings-display:before {
+ content: "\ea53";
+}
+.icon-settings-donottrack:before {
+ content: "\ea54";
+}
+.icon-settings-download:before {
+ content: "\ea55";
+}
+.icon-settings-email:before {
+ content: "\ea56";
+}
+.icon-settings-facerecognition:before {
+ content: "\ea57";
+}
+.icon-settings-feedback:before {
+ content: "\ea58";
+}
+.icon-settings-findmydevice:before {
+ content: "\ea59";
+}
+.icon-settings-fingerprint:before {
+ content: "\ea5a";
+}
+.icon-settings-fmradio-permissions:before {
+ content: "\ea5b";
+}
+.icon-settings-gesture:before {
+ content: "\ea5c";
+}
+.icon-settings-gps:before {
+ content: "\ea5d";
+}
+.icon-settings-gps-permissions:before {
+ content: "\ea5e";
+}
+.icon-settings-help:before {
+ content: "\ea5f";
+}
+.icon-settings-helpx:before {
+ content: "\ea60";
+}
+.icon-settings-homescreen:before {
+ content: "\ea61";
+}
+.icon-settings-irisscanner:before {
+ content: "\ea62";
+}
+.icon-settings-languages:before {
+ content: "\ea63";
+}
+.icon-settings-mediastorage:before {
+ content: "\ea64";
+}
+.icon-settings-messages:before {
+ content: "\ea65";
+}
+.icon-settings-network:before {
+ content: "\ea66";
+}
+.icon-settings-nfc:before {
+ content: "\ea67";
+}
+.icon-settings-notifications:before {
+ content: "\ea68";
+}
+.icon-settings-persona:before {
+ content: "\ea69";
+}
+.icon-settings-phonelock:before {
+ content: "\ea6a";
+}
+.icon-settings-privacy:before {
+ content: "\ea6b";
+}
+.icon-settings-simcardlock:before {
+ content: "\ea6c";
+}
+.icon-settings-simtoolkit:before {
+ content: "\ea6d";
+}
+.icon-settings-sound-max:before {
+ content: "\ea6e";
+}
+.icon-settings-sound-min:before {
+ content: "\ea6f";
+}
+.icon-settings-tethering:before {
+ content: "\ea70";
+}
+.icon-settings-themes:before {
+ content: "\ea71";
+}
+.icon-settings-time:before {
+ content: "\ea72";
+}
+.icon-settings-usbstorage:before {
+ content: "\ea73";
+}
+.icon-settings-wallpaper:before {
+ content: "\ea74";
+}
+.icon-settings-wifi:before {
+ content: "\ea75";
+}
+.icon-settings-wifi-1:before {
+ content: "\ea76";
+}
+.icon-settings-wifi-2:before {
+ content: "\ea77";
+}
+.icon-settings-wifi-3:before {
+ content: "\ea78";
+}
+.icon-settings-wifi-4:before {
+ content: "\ea79";
+}
+.icon-settings-wifi-lock:before {
+ content: "\ea7a";
+}
+.icon-settings-wifi-lock-1:before {
+ content: "\ea7b";
+}
+.icon-settings-wifi-lock-2:before {
+ content: "\ea7c";
+}
+.icon-settings-wifi-lock-3:before {
+ content: "\ea7d";
+}
+.icon-settings-wifi-lock-4:before {
+ content: "\ea7e";
+}
+.icon-settings-wifi-permissions:before {
+ content: "\ea7f";
+}
+.icon-share:before {
+ content: "\ea80";
+}
+.icon-shopping-cart:before {
+ content: "\ea81";
+}
+.icon-shuffle:before {
+ content: "\ea82";
+}
+.icon-side-tabs:before {
+ content: "\ea83";
+}
+.icon-signal-1:before {
+ content: "\ea84";
+}
+.icon-signal-2:before {
+ content: "\ea85";
+}
+.icon-signal-3:before {
+ content: "\ea86";
+}
+.icon-signal-4:before {
+ content: "\ea87";
+}
+.icon-signal-5:before {
+ content: "\ea88";
+}
+.icon-sim:before {
+ content: "\ea89";
+}
+.icon-skip-back:before {
+ content: "\ea8a";
+}
+.icon-skip-forward:before {
+ content: "\ea8b";
+}
+.icon-sms:before {
+ content: "\ea8c";
+}
+.icon-snap-bottom:before {
+ content: "\ea8d";
+}
+.icon-snap-bottom-left:before {
+ content: "\ea8e";
+}
+.icon-snap-bottom-right:before {
+ content: "\ea8f";
+}
+.icon-snap-left:before {
+ content: "\ea90";
+}
+.icon-snap-right:before {
+ content: "\ea91";
+}
+.icon-snap-top:before {
+ content: "\ea92";
+}
+.icon-snap-top-left:before {
+ content: "\ea93";
+}
+.icon-snap-top-right:before {
+ content: "\ea94";
+}
+.icon-songs:before {
+ content: "\ea95";
+}
+.icon-sound-max:before {
+ content: "\ea96";
+}
+.icon-sound-min:before {
+ content: "\ea97";
+}
+.icon-speaker:before {
+ content: "\ea98";
+}
+.icon-splitscreen:before {
+ content: "\ea99";
+}
+.icon-spotify-svgrepo-com:before {
+ content: "\ea9a";
+}
+.icon-ssl:before {
+ content: "\ea9b";
+}
+.icon-ssl-broken:before {
+ content: "\ea9c";
+}
+.icon-stickers:before {
+ content: "\ea9d";
+}
+.icon-storage:before {
+ content: "\ea9e";
+}
+.icon-sync:before {
+ content: "\ea9f";
+}
+.icon-tab-previews:before {
+ content: "\eaa1";
+}
+.icon-tablet:before {
+ content: "\eaa0";
+}
+.icon-taskswitcherappclose-circle:before {
+ content: "\eaa2";
+}
+.icon-taskswitcherappclose-cross:before {
+ content: "\eaa3";
+}
+.icon-television:before {
+ content: "\eaa4";
+}
+.icon-tethering:before {
+ content: "\eaa5";
+}
+.icon-textselection-copy:before {
+ content: "\eaa6";
+}
+.icon-textselection-cut:before {
+ content: "\eaa7";
+}
+.icon-textselection-paste:before {
+ content: "\eaa8";
+}
+.icon-textselection-selectall:before {
+ content: "\eaa9";
+}
+.icon-themes:before {
+ content: "\eaaa";
+}
+.icon-threadnotsent-circle:before {
+ content: "\eaab";
+}
+.icon-threadnotsent-exclamation:before {
+ content: "\eaac";
+}
+.icon-tick:before {
+ content: "\eaad";
+}
+.icon-tick-circle:before {
+ content: "\eaae";
+}
+.icon-tiktok:before {
+ content: "\eaaf";
+}
+.icon-time:before {
+ content: "\eab0";
+}
+.icon-treadsent-check:before {
+ content: "\eab1";
+}
+.icon-treadsent-circle:before {
+ content: "\eab2";
+}
+.icon-tree:before {
+ content: "\eab3";
+}
+.icon-tv:before {
+ content: "\eab4";
+}
+.icon-twitch:before {
+ content: "\eab5";
+}
+.icon-twitter:before {
+ content: "\eab6";
+}
+.icon-undo:before {
+ content: "\eab7";
+}
+.icon-upload:before {
+ content: "\eab8";
+}
+.icon-usb:before {
+ content: "\eab9";
+}
+.icon-user:before {
+ content: "\eaba";
+}
+.icon-useraccoun-headers:before {
+ content: "\eabb";
+}
+.icon-utility-airplanemode:before {
+ content: "\eabc";
+}
+.icon-utility-arrow:before {
+ content: "\eabd";
+}
+.icon-utility-battery:before {
+ content: "\eabe";
+}
+.icon-utility-bluetooth:before {
+ content: "\eabf";
+}
+.icon-utility-brightness:before {
+ content: "\eac0";
+}
+.icon-utility-camera-lockedscreen:before {
+ content: "\eac1";
+}
+.icon-utility-data:before {
+ content: "\eac2";
+}
+.icon-utility-flashlight:before {
+ content: "\eac3";
+}
+.icon-utility-maxvolume:before {
+ content: "\eac4";
+}
+.icon-utility-mute-cease:before {
+ content: "\eac5";
+}
+.icon-utility-mute-speaker:before {
+ content: "\eac6";
+}
+.icon-utility-vibrate:before {
+ content: "\eac7";
+}
+.icon-utility-volume:before {
+ content: "\eac8";
+}
+.icon-utility-wifi:before {
+ content: "\eac9";
+}
+.icon-vibrate:before {
+ content: "\eaca";
+}
+.icon-video:before {
+ content: "\eacb";
+}
+.icon-vpn:before {
+ content: "\eacc";
+}
+.icon-wallpaper:before {
+ content: "\eacd";
+}
+.icon-web:before {
+ content: "\eace";
+}
+.icon-wifi:before {
+ content: "\eacf";
+}
+.icon-wifi-1:before {
+ content: "\ead0";
+}
+.icon-wifi-2:before {
+ content: "\ead1";
+}
+.icon-wifi-3:before {
+ content: "\ead2";
+}
+.icon-wifi-4:before {
+ content: "\ead3";
+}
+.icon-windows:before {
+ content: "\ead4";
+}
+.icon-wm-snapbottom:before {
+ content: "\ead5";
+}
+.icon-wm-snapbottomleft:before {
+ content: "\ead6";
+}
+.icon-wm-snapbottomright:before {
+ content: "\ead7";
+}
+.icon-wm-snapleft:before {
+ content: "\ead8";
+}
+.icon-wm-snapright:before {
+ content: "\ead9";
+}
+.icon-wm-snaptop:before {
+ content: "\eada";
+}
+.icon-wm-snaptopleft:before {
+ content: "\eadb";
+}
+.icon-wm-snaptopright:before {
+ content: "\eadc";
+}
+.icon-youtube:before {
+ content: "\eadd";
+}
diff --git a/shared/style/lists.css b/shared/style/lists.css
new file mode 100644
index 0000000..eb62410
--- /dev/null
+++ b/shared/style/lists.css
@@ -0,0 +1,122 @@
+.lists header {
+ width: 100%;
+ max-width: 74.8rem;
+ padding: 0 2rem;
+ box-sizing: border-box;
+ height: 3rem;
+ line-height: 3rem;
+ color: #858585;
+ font-size: 1.6rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin: 1rem auto 0;
+}
+
+.lists ul {
+ margin: 0 auto 1.5rem;
+ padding: 0.5rem;
+ background-color: var(--background-plus);
+ border-radius: 1.5rem;
+ width: calc(100% - 3rem);
+ max-width: 71.8rem;
+ box-sizing: border-box;
+}
+
+.lists ul li {
+ position: relative;
+ margin: 0;
+ list-style: none;
+ min-height: 5rem;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ width: 100%;
+ padding: 0 1.5rem;
+ box-sizing: border-box;
+ border-radius: 1rem;
+ color: var(--text-color);
+}
+
+.lists ul li:hover {
+ background-color: var(--item-hover);
+}
+
+.lists ul li:active {
+ background-color: var(--item-active);
+}
+
+.lists ul li.selected {
+ background-color: var(--accent-color);
+ color: var(--accent-color-plus);
+}
+
+.lists ul li[data-icon] {
+ padding-inline-start: 4.5rem;
+}
+
+.lists ul li[data-icon]::before {
+ position: absolute;
+ top: 50%;
+ margin-top: -1.2rem;
+ left: 1.2rem;
+ color: var(--text-color);
+ width: 2.4rem;
+ height: 2.4rem;
+ line-height: 2.4rem;
+ font-size: 2.4rem;
+}
+
+.lists ul li.selected[data-icon]::before {
+ color: var(--accent-color-plus);
+}
+
+.lists ul li.page::after {
+ content: 'forward';
+ font-family: "openorchid-icons";
+ font-size: 2rem;
+ color: #858585;
+ text-align: end;
+ line-height: 5rem;
+}
+
+.lists ul li.page.selected::after {
+ color: var(--accent-color-plus);
+ opacity: 0.5;
+}
+
+.lists ul li::after {
+ content: '';
+ position: absolute;
+ left: 1.5rem;
+ top: 0;
+ width: calc(100% - 3rem);
+ height: 100%;
+ pointer-events: none;
+ border-bottom: solid 0.1rem var(--item-hover);
+ box-sizing: border-box;
+}
+
+.lists ul li:hover::after,
+.lists ul li:active::after,
+.lists ul li:last-child::after {
+ border-bottom: none;
+}
+
+.lists ul li p {
+ margin: 0;
+ height: 2.2rem;
+ line-height: 2.2rem;
+ font-size: 1.6rem;
+ color: var(--text-color);
+}
+
+.lists ul li.selected p {
+ color: var(--accent-color-plus);
+}
+
+.lists ul li p:not(:first-child) {
+ height: 1.9rem;
+ line-height: 1.9rem;
+ font-size: 1.4rem;
+ opacity: 0.5;
+}
diff --git a/shared/style/main.css b/shared/style/main.css
new file mode 100644
index 0000000..e2c8636
--- /dev/null
+++ b/shared/style/main.css
@@ -0,0 +1,15 @@
+html, body {
+ margin: 0;
+ padding: 0;
+ font-size: 10px;
+}
+
+.app {
+ --statusbar-height: 4rem;
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--background);
+}
diff --git a/shared/style/panels.css b/shared/style/panels.css
new file mode 100644
index 0000000..b05a798
--- /dev/null
+++ b/shared/style/panels.css
@@ -0,0 +1,100 @@
+.panel {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--background);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ z-index: 50;
+}
+
+.panel > .content {
+ width: 100%;
+ height: 100%;
+ flex-grow: 1;
+ overflow-y: auto;
+ margin-top: calc((-5rem - var(--statusbar-height)) * var(--progress, 0));
+ scrollbar-width: none;
+}
+
+.panel > .content aside {
+ margin: 0 auto 1.5rem;
+ padding: 0;
+ background-color: var(--background-minus);
+ border-radius: 1.5rem;
+ width: calc(100% - 3rem);
+ max-width: 71.8rem;
+ box-sizing: border-box;
+}
+
+.panel > .content aside header {
+ width: 100%;
+ padding: 0 2rem;
+ box-sizing: border-box;
+ height: 3rem;
+ line-height: 3rem;
+ color: #858585;
+ font-size: 1.6rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin: 1rem 0 0;
+}
+
+.panel > .content aside ul {
+ margin: 0;
+ padding: 0 0.5rem 0.5rem;
+ width: 100%;
+ background-color: transparent;
+}
+
+.panel > .content aside ul li {
+ min-height: 3.2rem;
+ background-color: transparent;
+}
+
+.panel > .content aside ul li > a {
+ color: var(--accent-color);
+ width: max-content;
+ line-height: 2.2rem;
+ font-size: 1.6rem;
+ text-decoration: none;
+ transition: box-shadow 0.2s ease;
+}
+
+.panel > .content aside ul li > a:hover {
+ box-shadow: 0 0.2rem 0 var(--accent-color);
+}
+
+.panel > .content aside ul li > a:active {
+ opacity: 0.5;
+}
+
+@media screen and (min-width: 983px) {
+ .panel > .headerbar .safezone {
+ margin-inline-start: 0;
+ }
+
+ .panel > .content header,
+ .panel > .content ul {
+ margin-inline-start: 1.5rem;
+ }
+
+ .panel > .content aside {
+ position: absolute;
+ right: 0;
+ top: calc(5rem + var(--statusbar-height) + (4rem * (1 - var(--progress, 0))));
+ width: 22rem;
+ margin: calc(1.5rem * var(--progress, 0)) 1.5rem 1.5rem;
+ }
+}
+
+@media screen and (min-width: 1536px) {
+ .panel > .headerbar .safezone,
+ .panel > .content header,
+ .panel > .content ul {
+ margin-inline-start: auto;
+ }
+}
diff --git a/shared/style/switches.css b/shared/style/switches.css
new file mode 100644
index 0000000..be56c72
--- /dev/null
+++ b/shared/style/switches.css
@@ -0,0 +1,83 @@
+.pack-switch {
+ width: 100%;
+ display: inline-flex;
+}
+
+.pack-switch > label {
+ width: 100%;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ flex-grow: 1;
+}
+
+.pack-switch > span {
+ flex-shrink: 0;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.pack-switch > span input[type="checkbox"] {
+ background-color: var(--switch-normal);
+ width: 5rem;
+ height: 2.5rem;
+ border-radius: 2.5rem;
+ border: none;
+ position: relative;
+ outline: none;
+ appearance: none;
+ transition: all 0.1s ease;
+}
+
+.pack-switch > span input[type="checkbox"]:hover {
+ background-color: var(--switch-hover);
+}
+
+.pack-switch > span input[type="checkbox"]:hover {
+ background-color: var(--switch-active);
+}
+
+.pack-switch > span input[type="checkbox"]:checked {
+ background-color: var(--accent-color);
+}
+
+.pack-switch > span input[type="checkbox"]::before {
+ content: '';
+ position: absolute;
+ left: 0.5rem;
+ top: 0.5rem;
+ width: 1.5rem;
+ height: 1.5rem;
+ background-color: var(--text-color);
+ border-radius: 1.5rem;
+ transition: all 0.3s cubic-bezier(0.2, 0, 0, 1);
+ z-index: 1;
+ pointer-events: none;
+}
+
+.pack-switch > span input[type="checkbox"]:hover::before {
+ transform: scale(1.2);
+}
+
+.pack-switch > span input[type="checkbox"]:active::before {
+ transform: scale(0.8);
+ width: 4rem;
+}
+
+.pack-switch > span input[type="checkbox"]:checked::before {
+ left: 3rem;
+ transform: scale(1);
+ background-color: var(--accent-color-plus);
+}
+
+.pack-switch > span input[type="checkbox"]:checked:hover::before {
+ transform: scale(1.2);
+}
+
+.pack-switch > span input[type="checkbox"]:checked:active::before {
+ left: 0.5rem;
+ transform: scale(0.8);
+ width: 4rem;
+}
\ No newline at end of file
diff --git a/shared/style/tablists.css b/shared/style/tablists.css
new file mode 100644
index 0000000..e69de29
diff --git a/shared/style/theme.css b/shared/style/theme.css
new file mode 100644
index 0000000..3690514
--- /dev/null
+++ b/shared/style/theme.css
@@ -0,0 +1,61 @@
+:root {
+ --accent-color: #0061e0;
+ --accent-color-plus: rgba(255, 255, 255, 0.75);
+ --accent-color-hover: rgba(255, 255, 255, 0.05);
+ --accent-color-active: rgba(255, 255, 255, 0.1);
+
+ --background: #f0f6ff;
+ --background-plus: #fff;
+ --background-minus: #e0edff;
+
+ --acrylic-background: rgba(224, 237, 255, 0.5);
+ --acrylic-background-plus: rgba(255, 255, 255, 0.75);
+
+ --text-color: #333;
+
+ --item-plus: rgba(0, 0, 0, 0.05);
+ --item-hover: rgba(0, 0, 0, 0.05);
+ --item-hover-plus: rgba(0, 0, 0, 0.1);
+ --item-active: rgba(0, 0, 0, 0.1);
+ --item-active-plus: rgba(0, 0, 0, 0.15);
+
+ --headerbar-r: 224;
+ --headerbar-g: 237;
+ --headerbar-b: 255;
+
+ --switch-normal: #d0e3ff;
+ --switch-hover: #c0d9ff;
+ --switch-active: #b0d0ff;
+}
+
+@media screen and (prefers-color-scheme: dark) {
+ :root {
+ --accent-color: #80c2ff;
+ --accent-color-plus: rgba(0, 0, 0, 0.75);
+ --accent-color-hover: rgba(0, 0, 0, 0.05);
+ --accent-color-active: rgba(0, 0, 0, 0.1);
+
+ --background: #000;
+ --background-plus: #212326;
+ --background-minus: #101215;
+
+ --acrylic-background: rgba(16, 18, 21, 0.5);
+ --acrylic-background-plus: rgba(33, 35, 38, 0.75);
+
+ --text-color: #e7e7e7;
+
+ --item-plus: rgba(255, 255, 255, 0.05);
+ --item-hover: rgba(255, 255, 255, 0.05);
+ --item-hover-plus: rgba(255, 255, 255, 0.1);
+ --item-active: rgba(255, 255, 255, 0.1);
+ --item-active-plus: rgba(255, 255, 255, 0.15);
+
+ --headerbar-r: 16;
+ --headerbar-g: 18;
+ --headerbar-b: 21;
+
+ --switch-normal: #101215;
+ --switch-hover: #303235;
+ --switch-active: #404245;
+ }
+}
diff --git a/shared/style/webview.css b/shared/style/webview.css
new file mode 100644
index 0000000..b81fc92
--- /dev/null
+++ b/shared/style/webview.css
@@ -0,0 +1,17 @@
+*, ::placeholder {
+ font-family: system-ui;
+}
+
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: #858585;
+ background-clip: content-box;
+ border: 2px solid transparent;
+ border-radius: 8px;
+ width: 8px;
+ height: 8px;
+}
diff --git a/style/brightness.css b/style/brightness.css
new file mode 100644
index 0000000..7284531
--- /dev/null
+++ b/style/brightness.css
@@ -0,0 +1,57 @@
+#brightness {
+ width: 100%;
+ background-color: var(--background-plus);
+ border-radius: 2rem;
+ height: 5rem;
+ display: flex;
+ padding: 0 1.5rem;
+ box-sizing: border-box;
+}
+
+#brightness > span {
+ height: 5rem;
+ line-height: 5rem;
+ color: var(--text-color);
+}
+
+#brightness > span[data-icon]::before {
+ font-size: 2.4rem;
+}
+
+#brightness-slider {
+ width: 100%;
+ height: 2.4rem;
+ background-color: rgba(0, 0, 0, 0.125);
+ border-radius: 2rem;
+ margin: 1.3rem 1rem;
+ position: relative;
+}
+
+#brightness-slider::before {
+ content: '';
+ position: absolute;
+ width: calc(100% * var(--progress, 0.5));
+ height: 2.4rem;
+ background-color: var(--accent-color);
+ border-radius: 2rem;
+}
+
+#brightness-slider > .thumb {
+ content: '';
+ position: absolute;
+ width: 1.6rem;
+ height: 1.6rem;
+ background-color: var(--accent-color-plus);
+ border-radius: 2rem;
+ left: calc((100% - 4rem) * var(--progress, 0.5));
+ top: 0.4rem;
+ transition: all 0.3s cubic-bezier(0.2, 0, 0, 1);
+}
+
+#brightness-slider:hover > .thumb {
+ transform: scale(1.2);
+}
+
+#brightness-slider:active > .thumb {
+ transform: scale(0.8);
+}
diff --git a/style/cards_view.css b/style/cards_view.css
new file mode 100644
index 0000000..8b7dccd
--- /dev/null
+++ b/style/cards_view.css
@@ -0,0 +1,3 @@
+#cards-view {
+ visibility: hidden;
+}
diff --git a/style/chrome.css b/style/chrome.css
new file mode 100644
index 0000000..77fec11
--- /dev/null
+++ b/style/chrome.css
@@ -0,0 +1,249 @@
+.chrome {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+.chrome .toolbar {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ padding: var(--statusbar-height, var(--chrome-toolbar-gap)) 0 var(--chrome-toolbar-gap);
+ box-sizing: border-box;
+ background-color: var(--theme-color, var(--background));
+ transform: translateX(-100%);
+ visibility: hidden;
+ gap: var(--chrome-toolbar-gap);
+ overflow: hidden;
+ z-index: 10;
+ transition: all 0.5s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+.chrome.visible .toolbar {
+ transform: translateY(0);
+ visibility: visible;
+}
+
+.chrome .tablist-holder {
+ width: 100%;
+ height: 4rem;
+ background-color: var(--theme-color, var(--background));
+ flex-shrink: 0;
+ display: flex;
+ padding: 0 0.5rem;
+ box-sizing: border-box;
+ gap: var(--chrome-toolbar-gap);
+}
+
+.chrome.hidden .tablist-holder {
+ display: none;
+}
+
+.chrome .tablist {
+ height: 4rem;
+ display: flex;
+ gap: var(--chrome-toolbar-gap);
+ margin: 0;
+ padding: 0;
+}
+
+.chrome .tablist li {
+ width: 24rem;
+ height: 4rem;
+ display: flex;
+ gap: var(--chrome-toolbar-gap);
+ list-style: none;
+ border-radius: 2rem;
+ margin: 0;
+ padding: 0 1rem;
+ padding-inline-end: 0.5rem;
+ box-sizing: border-box;
+ align-items: center;
+}
+
+.chrome .tablist li.active {
+ background-color: var(--item-hover);
+}
+
+.chrome .tablist li > .favicon {
+ width: 2rem;
+ height: 2rem;
+ flex-shrink: 0;
+}
+
+.chrome .tablist li > .title {
+ width: 100%;
+ flex-grow: 1;
+ height: 2rem;
+ line-height: 2rem;
+ font-size: 1.4rem;
+ color: var(--text-color);
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.chrome .tablist li > .close-button {
+ width: 3.2rem;
+ height: 3.2rem;
+ line-height: 3.2rem;
+ border: none;
+ background-color: transparent;
+ margin: 0;
+ padding: 0;
+ text-align: center;
+ color: var(--text-color);
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+.chrome .tablist li > .close-button:hover {
+ background-color: var(--item-hover);
+}
+
+.chrome .tablist li > .close-button:active {
+ background-color: var(--item-active);
+}
+
+.chrome .tablist li > .close-button[data-icon]::before {
+ font-size: 1.6rem;
+}
+
+.chrome .navbar {
+ width: 100%;
+ height: 4rem;
+ background-color: var(--theme-color, var(--background));
+ flex-shrink: 0;
+ display: flex;
+ padding: 0 0.5rem;
+ box-sizing: border-box;
+ gap: var(--chrome-toolbar-gap);
+}
+
+.chrome .tablist-holder > button,
+.chrome .navbar button {
+ min-width: 4rem;
+ height: 4rem;
+ line-height: 4rem;
+ margin: 0;
+ padding: 0 1rem;
+ box-sizing: border-box;
+ border: none;
+ border-radius: 50%;
+ flex-shrink: 0;
+ background-color: transparent;
+ color: var(--text-color);
+ font-size: 1.6rem;
+ text-align: center;
+}
+
+.chrome .tablist-holder > button[data-icon]::before,
+.chrome .navbar button[data-icon]::before {
+ font-size: 2rem;
+}
+
+.chrome .tablist-holder > button:hover,
+.chrome .navbar button:hover {
+ background-color: var(--item-hover);
+}
+
+.chrome .tablist-holder > button:active,
+.chrome .navbar button:active {
+ background-color: var(--item-active);
+}
+
+/* .chrome .tablist-holder > button {
+ background-color: var(--item-hover);
+}
+
+.chrome .tablist-holder > button:hover {
+ background-color: var(--item-hover-plus);
+}
+
+.chrome .tablist-holder > button:active {
+ background-color: var(--item-active-plus);
+} */
+
+.chrome .navbar .urlbar {
+ width: 100%;
+ height: 4rem;
+ display: flex;
+ border-radius: 2rem;
+ margin: 0;
+ padding: 0;
+ background-color: var(--item-hover);
+ flex-grow: 1;
+ overflow: hidden;
+}
+
+.chrome .navbar .urlbar > .urlbar-input {
+ width: 100%;
+ height: 4rem;
+ line-height: 4rem;
+ margin: 0;
+ padding: 0;
+ border: none;
+ background-color: transparent;
+ color: var(--text-color);
+ font-size: 1.6rem;
+ flex-grow: 1;
+ outline: none;
+ display: none;
+}
+
+.chrome .navbar .urlbar > .urlbar-display-url {
+ width: 100%;
+ height: 4rem;
+ line-height: 4rem;
+ color: var(--text-color);
+ font-size: 1.6rem;
+ flex-grow: 1;
+ display: flex;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.chrome .navbar .urlbar:hover > .urlbar-input,
+.chrome .navbar .urlbar:focus-within > .urlbar-input {
+ display: block;
+}
+
+.chrome .navbar .urlbar:hover > .urlbar-display-url,
+.chrome .navbar .urlbar:focus-within > .urlbar-display-url {
+ display: none;
+}
+
+.chrome .navbar .urlbar > .urlbar-display-url .ignored {
+ opacity: 0.5;
+}
+
+.chrome .browser-container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ flex-grow: 1;
+}
+
+.chrome .browser-container > .browser {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ visibility: hidden;
+}
+
+.chrome .browser-container > .browser.active {
+ visibility: visible;
+}
+
+#screen.context-menu-visible .chrome .browser-container > .browser {
+ pointer-events: none;
+}
diff --git a/style/icons/battery-0.svg b/style/icons/battery-0.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-0.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-10.svg b/style/icons/battery-10.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-10.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-100.svg b/style/icons/battery-100.svg
new file mode 100644
index 0000000..45628bd
--- /dev/null
+++ b/style/icons/battery-100.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-20.svg b/style/icons/battery-20.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-20.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-30.svg b/style/icons/battery-30.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-30.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-40.svg b/style/icons/battery-40.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-40.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-50.svg b/style/icons/battery-50.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-50.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-60.svg b/style/icons/battery-60.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-60.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-70.svg b/style/icons/battery-70.svg
new file mode 100644
index 0000000..58a5f37
--- /dev/null
+++ b/style/icons/battery-70.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-80.svg b/style/icons/battery-80.svg
new file mode 100644
index 0000000..029d33c
--- /dev/null
+++ b/style/icons/battery-80.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/icons/battery-90.svg b/style/icons/battery-90.svg
new file mode 100644
index 0000000..0f7142a
--- /dev/null
+++ b/style/icons/battery-90.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/style/images/back.png b/style/images/back.png
new file mode 100644
index 0000000..f30b7cb
Binary files /dev/null and b/style/images/back.png differ
diff --git a/style/images/back.svg b/style/images/back.svg
new file mode 100644
index 0000000..5f68225
--- /dev/null
+++ b/style/images/back.svg
@@ -0,0 +1,10 @@
+
diff --git a/style/images/home.png b/style/images/home.png
new file mode 100644
index 0000000..a8fffc0
Binary files /dev/null and b/style/images/home.png differ
diff --git a/style/images/home.svg b/style/images/home.svg
new file mode 100644
index 0000000..da2654f
--- /dev/null
+++ b/style/images/home.svg
@@ -0,0 +1,3 @@
+
diff --git a/style/images/recents.png b/style/images/recents.png
new file mode 100644
index 0000000..9458bc4
Binary files /dev/null and b/style/images/recents.png differ
diff --git a/style/images/recents.svg b/style/images/recents.svg
new file mode 100644
index 0000000..81f24a9
--- /dev/null
+++ b/style/images/recents.svg
@@ -0,0 +1,3 @@
+
diff --git a/style/images/splitscreen.png b/style/images/splitscreen.png
new file mode 100644
index 0000000..3182c49
Binary files /dev/null and b/style/images/splitscreen.png differ
diff --git a/style/images/splitscreen.svg b/style/images/splitscreen.svg
new file mode 100644
index 0000000..e67a8d5
--- /dev/null
+++ b/style/images/splitscreen.svg
@@ -0,0 +1,4 @@
+
diff --git a/style/keyboard.css b/style/keyboard.css
new file mode 100644
index 0000000..97f3f68
--- /dev/null
+++ b/style/keyboard.css
@@ -0,0 +1,210 @@
+#keyboard {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: 40%;
+ background-color: var(--background);
+ padding: 0.5rem;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ z-index: 2048;
+ transform: translateY(100%);
+ transition: all 0.5s cubic-bezier(0.8, 0.1, 0.9, 0);
+}
+
+#screen.software-buttons-enabled #keyboard {
+ height: calc(40% + var(--software-buttons-height));
+ padding-bottom: var(--software-buttons-height);
+}
+
+#keyboard.visible {
+ transform: translateY(0);
+ transition: all 0.5s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#keyboard-content {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ flex-grow: 1;
+ margin: 0 auto;
+ width: 100%;
+ max-width: 76.8rem;
+}
+
+#keyboard-content .row {
+ display: flex;
+ gap: 0.5rem;
+ flex-grow: 1;
+}
+
+#keyboard-content .row .key {
+ background-color: var(--background-plus);
+ border: none;
+ border-radius: 1rem;
+ color: var(--text-color);
+ font-size: 1.6rem;
+ margin: 0;
+ padding: 0;
+ min-height: 3rem;
+ line-height: 100%;
+ flex-grow: 1;
+ width: 100%;
+ position: relative;
+}
+
+#keyboard-content .row .key:not(.has-popout):active {
+ opacity: 0.75;
+}
+
+#keyboard-content .row .key .popout {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: calc(100% + 4rem);
+ min-height: 3rem;
+ line-height: 4rem;
+ background-color: var(--accent-color);
+ border-radius: 1rem;
+ color: var(--accent-color-plus);
+ font-size: 1.6rem;
+ transition: all 0.2s cubic-bezier(0.2, 0.9, 0.1, 1);
+ visibility: visible;
+ transform: scaleY(0.75);
+ transform-origin: bottom;
+ opacity: 0;
+ pointer-events: none;
+}
+
+#keyboard-content .row .key.has-popout:active .popout {
+ visibility: visible;
+ transform: scaleY(1);
+ opacity: 1;
+}
+
+#keyboard-content .row .key.backspace,
+#keyboard-content .row .key.symbols,
+#keyboard-content .row .key.letters {
+ background-color: var(--background);
+ border-radius: 9999px;
+}
+
+#keyboard-content .row .key.return {
+ background-color: var(--accent-color);
+ color: var(--accent-color-plus);
+ border-radius: 9999px;
+}
+
+#keyboard-content .row .key.space {
+ width: 175%;
+ border-radius: 9999px;
+}
+
+#keyboard-content .row .key.shift,
+#keyboard-content .row .key.backspace {
+ width: 150%;
+}
+
+#keyboard-content .row .key.shift[data-icon]::before,
+#keyboard-content .row .key.backspace[data-icon]::before {
+ font-size: 2rem;
+}
+
+#keyboard-toolbar {
+ flex-shrink: 0;
+ height: 4rem;
+ width: 100%;
+ display: flex;
+ margin: 0 auto;
+ margin-top: 1rem;
+ width: 100%;
+ max-width: 76.8rem;
+}
+
+#keyboard-toolbar button {
+ color: var(--text-color);
+ background-color: transparent;
+ border: none;
+ width: 4rem;
+ height: 4rem;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+#keyboard-toolbar button[data-icon]::before {
+ font-size: 2rem;
+}
+
+#keyboard-toolbar .spacer {
+ height: 4rem;
+ width: 100%;
+ flex-grow: 1;
+}
+
+#keyboard-auto-correct {
+ display: flex;
+ height: 3.6rem;
+ margin: 0 auto;
+ margin-bottom: 0.5rem;
+ width: 100%;
+ max-width: 76.8rem;
+}
+
+#keyboard-auto-correct > .suggestion {
+ flex-grow: 1;
+ height: 3.6rem;
+ line-height: 3.6rem;
+ width: 100%;
+ color: var(--text-color);
+ opacity: 0.5;
+ text-align: center;
+ font-size: 1.4rem;
+ border-radius: 2rem;
+}
+
+#keyboard-auto-correct > .suggestion:nth-child(2) {
+ opacity: 1;
+ background-color: var(--background-plus);
+}
+
+/* Languages Dropdown */
+#keyboard-languages {
+ position: absolute;
+ left: 1rem;
+ bottom: 4rem;
+ width: 15rem;
+ height: 100%;
+ background: var(--background-plus);
+ border-radius: 1.5rem;
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.3);
+ overflow-y: auto;
+ padding: 0.5rem;
+ box-sizing: border-box;
+ visibility: hidden;
+ opacity: 0;
+ transform: translateY(-1rem);
+}
+
+#screen.software-buttons-enabled #keyboard-languages {
+ bottom: calc(var(--software-buttons-height) + 4rem);
+}
+
+#keyboard-languages .language {
+ padding: 0 1rem;
+ box-sizing: border-box;
+ width: 100%;
+ height: 4rem;
+ line-height: 4rem;
+ color: var(--text-color);
+ font-size: 1.6rem;
+ display: flex;
+ align-items: center;
+}
+
+#keyboard-languages .language[data-icon]::before {
+ font-size: 2rem;
+ margin-inline-end: 1rem;
+}
diff --git a/style/lockscreen.css b/style/lockscreen.css
new file mode 100644
index 0000000..fa8492d
--- /dev/null
+++ b/style/lockscreen.css
@@ -0,0 +1,145 @@
+#lockscreen {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: #000;
+ opacity: 0;
+ visibility: hidden;
+ z-index: 16384;
+ transition: all 0.3s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#lockscreen.visible {
+ opacity: 1;
+ visibility: visible;
+}
+
+#lockscreen-background {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(to bottom, #00240c, rgb(0, 26, 42)) , url(/resources/wallpapers/default.png) no-repeat center / cover;
+ transform: scale(calc(1 + (0.125 * (1 - (1 - var(--motion-progress, 1))))));
+}
+
+#lockscreen.transitioning #lockscreen-background {
+ transition: all 0.3s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#lockscreen.low-power #lockscreen-background {
+ opacity: 0;
+ visibility: hidden;
+ transition: all 1s ease;
+}
+
+#lockscreen-container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.lockscreen-row {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ margin: 1.5rem 0;
+ align-items: center;
+ transform: scale(calc(1 - (0.125 * (1 - var(--motion-progress, 1)))));
+ opacity: var(--motion-progress, 1);
+}
+
+#lockscreen.transitioning .lockscreen-row {
+ transition: all 0.3s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#lockscreen.low-power .lockscreen-row {
+ margin: 3rem 0 0;
+ opacity: 0.75;
+ transition: all 1s ease;
+}
+
+#lockscreen-icon {
+ margin: 4.5rem 0 0;
+ color: #fff;
+ text-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.3);
+}
+
+#lockscreen-icon.fail-unlock {
+ animation: fail-unlock 0.75s ease-in-out;
+}
+
+@keyframes fail-unlock {
+ 0% {
+ transform: translateX(0);
+ }
+ 20% {
+ transform: translateX(1rem);
+ }
+ 40% {
+ transform: translateX(-0.75rem);
+ }
+ 60% {
+ transform: translateX(0.5rem);
+ }
+ 80% {
+ transform: translateX(-0.25rem);
+ }
+ 100% {
+ transform: translateX(0);
+ }
+}
+
+#lockscreen-clock {
+ font-size: 7.2rem;
+ font-weight: normal;
+ color: #fff;
+ line-height: 7.8rem;
+ text-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.3);
+}
+
+#lockscreen-date {
+ font-size: 2rem;
+ color: #fff;
+ text-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.3);
+}
+
+.lockscreen-hint {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ bottom: calc(25% * (1 - var(--motion-progress, 1)));
+ text-align: center;
+ padding: 0 1.5rem 2.5rem;
+ box-sizing: border-box;
+ pointer-events: none;
+ font-size: 1.6rem;
+ color: rgba(255, 255, 255, calc(var(--motion-progress, 1) * 0.5));
+}
+
+#lockscreen.transitioning .lockscreen-hint {
+ transition: all 0.3s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#lockscreen.low-power .lockscreen-hint {
+ opacity: 0.75;
+ color: transparent;
+ transition: all 1s ease;
+}
+
+.lockscreen-hint::before {
+ content: '';
+ position: absolute;
+ left: calc(100% / 3);
+ width: calc(100% / 3);
+ bottom: 1rem;
+ height: 0.5rem;
+ background-color: #fff;
+ border-radius: 0.5rem;
+ box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.3);
+}
diff --git a/style/media_playback.css b/style/media_playback.css
new file mode 100644
index 0000000..0391037
--- /dev/null
+++ b/style/media_playback.css
@@ -0,0 +1,66 @@
+#media-playback {
+ width: 100%;
+ flex-grow: 1;
+ background-color: var(--background-plus);
+ border-radius: 2rem;
+ min-height: 6.5rem;
+ position: relative;
+}
+
+#media-playback .content {
+ width: 100%;
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ padding: 1rem;
+ box-sizing: border-box;
+ color: var(--text-color);
+}
+
+#media-playback-title {
+ font-size: 1.5rem;
+ color: var(--text-color);
+ line-height: 2.1rem;
+}
+
+#media-playback-author {
+ font-size: 1.3rem;
+ color: var(--text-color);
+ line-height: 1.9rem;
+ opacity: 0.5;
+}
+
+#media-playback .content .buttons {
+ width: 100%;
+ height: 3.2rem;
+ display: flex;
+ gap: 0.8rem;
+ justify-content: center;
+ margin: 0.5rem 0 0;
+}
+
+#media-playback .content .buttons button {
+ width: 3.2rem;
+ height: 3.2rem;
+ line-height: 3.2rem;
+ background-color: var(--item-hover);
+ border-radius: 1.6rem;
+ color: var(--text-color);
+ text-align: center;
+ margin: 0;
+ padding: 0;
+ flex-shrink: 0;
+ border: none;
+}
+
+#media-playback .content .buttons button:hover {
+ background-color: var(--item-hover-plus);
+}
+
+#media-playback .content .buttons button:active {
+ background-color: var(--item-active-plus);
+}
+
+#media-playback .content .buttons button::before {
+ font-size: 2rem;
+}
diff --git a/style/notifications.css b/style/notifications.css
new file mode 100644
index 0000000..5bf1c37
--- /dev/null
+++ b/style/notifications.css
@@ -0,0 +1,152 @@
+#notification-toaster {
+ position: absolute;
+ left: 0;
+ top: var(--statusbar-height);
+ width: calc(100% - 2rem);
+ margin: 0 1rem;
+ background-color: var(--acrylic-background-plus);
+ backdrop-filter: blur(20px) saturate(180%);
+ box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.3);
+ z-index: 32768;
+ transform: translateY(calc(-100% - var(--statusbar-height) - 4.5rem));
+ transition: all 0.5s cubic-bezier(0.8, 0.1, 0.9, 0);
+}
+
+#notification-toaster.visible {
+ transform: translateY(0);
+ transition: all 0.5s cubic-bezier(0.2, 0.9, 0.1, 1.1);
+}
+
+.notification {
+ background-color: var(--background-plus);
+ border-radius: 2rem;
+ width: 100%;
+ margin: 0 0 1rem;
+}
+
+.notification .titlebar {
+ width: 100%;
+ padding: 1rem 1.5rem;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+}
+
+.notification .titlebar .badge {
+ width: 2rem;
+ height: 2rem;
+ margin-inline-end: 1rem;
+ flex-shrink: 0;
+}
+
+.notification .titlebar .source-name {
+ height: 2rem;
+ line-height: 2rem;
+ margin-inline-end: 1rem;
+ color: var(--text-color);
+ font-size: 1.4rem;
+ flex-grow: 1;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ width: 100%;
+}
+
+.notification .content {
+ width: 100%;
+ padding: 0 1.5rem 1rem;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+}
+
+.notification .content .icon {
+ width: 4.5rem;
+ height: 4.5rem;
+ margin-inline-end: 1rem;
+ flex-shrink: 0;
+}
+
+.notification .content .text-holder {
+ color: var(--text-color);
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ overflow: hidden;
+}
+
+.notification .content .text-holder .title {
+ color: var(--text-color);
+ font-size: 1.6rem;
+ line-height: 2.2rem;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ width: 100%;
+}
+
+.notification .content .text-holder .detail {
+ color: var(--text-color);
+ font-size: 1.4rem;
+ line-height: 2rem;
+ opacity: 0.5;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ width: 100%;
+}
+
+.notification .media {
+ width: 100%;
+ aspect-ratio: 16 / 9;
+ display: grid;
+ grid-template-columns: repeat(auto-fit, 1fr);
+ grid-template-rows: repeat(auto-fit, 1fr);
+ padding: 0 1.5rem 1rem;
+ box-sizing: border-box;
+}
+
+.notification .media:empty {
+ display: none;
+}
+
+.notification .media > img {
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+}
+
+.notification .actions {
+ width: 100%;
+ padding: 0 1.5rem 1rem;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
+
+.notification .actions button {
+ padding: 0 1.5rem;
+ box-sizing: border-box;
+ height: 3rem;
+ line-height: 3rem;
+ border-radius: 1.5rem;
+ border: none;
+ background-color: transparent;
+ color: var(--text-color);
+ font-size: 1.6rem;
+}
+
+.notification .actions button:hover {
+ background-color: var(--item-hover);
+}
+
+.notification .actions button:active {
+ background-color: var(--item-active);
+}
+
+.notification .actions button.recommend {
+ background-color: var(--accent-color);
+ color: var(--accent-color-plus);
+}
diff --git a/style/quick_settings.css b/style/quick_settings.css
new file mode 100644
index 0000000..d566fb3
--- /dev/null
+++ b/style/quick_settings.css
@@ -0,0 +1,153 @@
+#connection-settings {
+ width: 100%;
+ flex-grow: 1;
+ overflow: hidden;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+}
+
+#connection-settings li {
+ width: 12rem;
+ flex-grow: 1;
+ background-color: var(--background-plus);
+ border-radius: 2rem;
+ margin: 0;
+ height: 6.5rem;
+ list-style: none;
+}
+
+#quick-settings {
+ width: 100%;
+ flex-grow: 1;
+ overflow: hidden;
+ background-color: var(--background-plus);
+ border-radius: 2rem;
+}
+
+#quick-settings-grid {
+ width: 100%;
+ overflow: hidden;
+ margin: 0;
+ padding: 0 1rem;
+ box-sizing: border-box;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-around;
+}
+
+#quick-settings li {
+ width: 4rem;
+ height: 6.5rem;
+ aspect-ratio: 1 / 1;
+ list-style: none;
+}
+
+#connection-settings li > a,
+#quick-settings li > a {
+ width: 100%;
+ height: 100%;
+ line-height: 1;
+ display: inline-flex;
+ align-items: center;
+ text-decoration: none;
+ color: var(--text-color);
+ font-size: 1.4rem;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ padding-inline-start: 6.25rem;
+ box-sizing: border-box;
+ position: relative;
+}
+
+#quick-settings li > a {
+ padding: 0;
+ padding-inline-start: 0;
+}
+
+#connection-settings li > a[data-icon]::before,
+#quick-settings li > a[data-icon]::before {
+ width: 4rem;
+ background-color: var(--item-hover);
+ border-radius: 2rem;
+ height: 4rem;
+ line-height: 4rem;
+ margin: 1.25rem;
+ text-align: center;
+ font-size: 2.4rem;
+ flex-shrink: 0;
+ position: absolute;
+ left: 0;
+ top: 0;
+}
+
+#quick-settings li > a[data-icon]::before {
+ margin: 1.75rem 0 0.75rem;
+ position: relative;
+}
+
+#connection-settings li > a::after {
+ content: '';
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ top: 0;
+ border-radius: 2rem;
+}
+
+#connection-settings li > a:hover::after {
+ background-color: var(--item-hover);
+}
+
+#connection-settings li > a:active::after {
+ background-color: var(--item-active);
+}
+
+#quick-settings li > a:hover::before {
+ background-color: var(--item-hover-plus);
+}
+
+#quick-settings li > a:active::before {
+ background-color: var(--item-active-plus);
+}
+
+#connection-settings li.enabled,
+#quick-settings li.enabled > a::before {
+ background-color: var(--accent-color);
+ color: var(--accent-color-plus);
+}
+
+#connection-settings li.enabled > a,
+#quick-settings li.enabled > a {
+ color: var(--accent-color-plus);
+}
+
+#connection-settings li.enabled > a {
+ font-weight: bold;
+}
+
+#connection-settings li.enabled > a[data-icon]::before {
+ background-color: var(--accent-color-hover);
+}
+
+#quick-settings > .grippy-bar {
+ width: 100%;
+ height: 2rem;
+ position: relative;
+}
+
+#quick-settings > .grippy-bar::before {
+ content: '';
+ position: absolute;
+ left: 50%;
+ top: 0.25rem;
+ width: 5rem;
+ height: 0.5rem;
+ margin-left: -2.5rem;
+ background-color: var(--item-hover);
+ border-radius: 0.5rem;
+}
diff --git a/style/software_buttons.css b/style/software_buttons.css
new file mode 100644
index 0000000..2d6e30b
--- /dev/null
+++ b/style/software_buttons.css
@@ -0,0 +1,128 @@
+#software-buttons {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ bottom: 0;
+ height: var(--software-buttons-height);
+ display: flex;
+ justify-content: center;
+ z-index: 4096;
+}
+
+#screen:not(.keyboard-visible) #software-buttons.light {
+ filter: invert(1) hue-rotate(180deg);
+}
+
+#software-buttons.hidden {
+ transform: translateY(-100%);
+}
+
+#software-buttons > button {
+ position: relative;
+ width: 8rem;
+ height: 100%;
+ background: transparent no-repeat center / 1.75rem;
+ border: none;
+ opacity: 0.8;
+}
+
+#software-buttons > button::after {
+ content: '';
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ top: 0;
+ width: 0;
+ height: 100%;
+ border-radius: 9999px;
+ background: rgba(255, 255, 255, 0.1);
+ opacity: 0;
+ pointer-events: none;
+ transition: all 0.3s cubic-bezier(0.2, 0.9, 0.1, 1), width 0.1s ease 0.3s;
+}
+
+#software-buttons > button:active:after {
+ width: calc(100% + 1rem);
+ opacity: 1;
+ transition: all 0.3s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#software-buttons > #software-back-button {
+ background-image: url(images/back.png);
+}
+
+#software-buttons > #software-home-button {
+ background-image: url(images/home.png);
+}
+
+#software-buttons > #software-recents-button {
+ background-image: url(images/recents.png);
+}
+
+#software-buttons > #software-keyboard-button {
+ background-image: url(images/splitscreen.png);
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 5rem;
+}
+
+#dock {
+ height: var(--software-buttons-height);
+ display: flex;
+ padding-inline-start: 2.5rem;
+ gap: 1.5rem;
+}
+
+#dock .icon {
+ position: relative;
+ width: var(--software-buttons-height);
+ height: var(--software-buttons-height);
+}
+
+#dock .icon.expand {
+ animation: dock-expand 0.5s cubic-bezier(0.2, 0.9, 0.1, 1) forwards;
+}
+
+@keyframes dock-expand {
+ from {
+ transform: scale(0.75);
+ opacity: 0;
+ }
+ to {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+#dock .icon.shrink {
+ animation: dock-shrink 0.3s cubic-bezier(0.8, 0.1, 0.9, 0) forwards;
+}
+
+@keyframes dock-shrink {
+ from {
+ transform: scale(1);
+ opacity: 1;
+ }
+ to {
+ transform: scale(0.75);
+ opacity: 0;
+ }
+}
+
+#dock .icon > img {
+ width: calc(var(--software-buttons-height) - 1rem);
+ height: calc(var(--software-buttons-height) - 1rem);
+ margin: 0.5rem;
+ opacity: 0.75;
+}
+
+#dock .icon.active > img {
+ opacity: 1;
+}
+
+@media screen and (max-width: 767px) {
+ #dock {
+ display: none;
+ }
+}
diff --git a/style/splashscreen.css b/style/splashscreen.css
new file mode 100644
index 0000000..8ec9cea
--- /dev/null
+++ b/style/splashscreen.css
@@ -0,0 +1,29 @@
+#splashscreen {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: #000;
+ z-index: 65535;
+}
+
+#splashscreen.hidden {
+ opacity: 0;
+ visibility: hidden;
+ transition: all 0.5s ease 2s;
+}
+
+#splashscreen-video {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+#splashscreen.hidden #splashscreen-video {
+ transform: scale(0.9);
+ transition: all 0.5s ease 2s;
+}
diff --git a/style/statusbar.css b/style/statusbar.css
new file mode 100644
index 0000000..7fccc02
--- /dev/null
+++ b/style/statusbar.css
@@ -0,0 +1,143 @@
+#statusbar {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: var(--statusbar-height);
+ z-index: 32767;
+ transition: all 0.3s ease;
+}
+
+#statusbar.light {
+ filter: invert(1) hue-rotate(180deg);
+}
+
+#statusbar.hidden {
+ transform: translateY(-100%);
+}
+
+.statusbar-icons {
+ position: absolute;
+ left: 0;
+ top: 0;
+ margin: 0 var(--statusbar-padding-left) 0 var(--statusbar-padding-right);
+ width: calc(100% - var(--statusbar-padding-left) - var(--statusbar-padding-right));
+ height: 100%;
+ opacity: 0.8;
+}
+
+.statusbar-icons > .left {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 50%;
+ height: 100%;
+ display: flex;
+ justify-content: start;
+ align-items: center;
+}
+
+.statusbar-icons > .right {
+ position: absolute;
+ left: 50%;
+ top: 0;
+ width: 50%;
+ height: 100%;
+ display: flex;
+ justify-content: end;
+ flex-direction: row-reverse;
+ align-items: center;
+}
+
+.statusbar-icons > .left div,
+.statusbar-icons > .right div {
+ color: #fff;
+ min-width: 2rem;
+ height: 2rem;
+ line-height: 2rem;
+ margin: 0 0.2rem;
+ text-align: center;
+ transition: all 0.3s cubic-bezier(0.2, 0.9, 0.1, 1.25) 0.3s, margin 0.3s cubic-bezier(0.2, 0.9, 0.1, 1.25);
+}
+
+.statusbar-icons > .left .hidden,
+.statusbar-icons > .right .hidden {
+ opacity: 0;
+ transform: scale(0.2);
+ visibility: hidden;
+ margin: 0 -1rem;
+ transition: all 0.3s ease, margin 0.3s cubic-bezier(0.2, 0.9, 0.1, 1) 0.3s;
+}
+
+#statusbar-notifications::before {
+ width: 2rem;
+ height: 2rem;
+ line-height: 2rem;
+ font-size: 1.8rem;
+}
+
+#statusbar-time {
+ color: #fff;
+ font-size: 1.6rem;
+}
+
+#statusbar-battery::before {
+ width: 2rem;
+ height: 2rem;
+ line-height: 2rem;
+ font-size: 1.8rem;
+}
+
+#statusbar-cellular-signal {
+ position: relative;
+}
+
+#statusbar-cellular-signal::before {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 2rem;
+ height: 2rem;
+ line-height: 2rem;
+ font-size: 1.8rem;
+}
+
+#statusbar-cellular-signal::after {
+ content: 'signal-5';
+ position: absolute;
+ left: 0;
+ top: 0;
+ font-family: "openorchid-icons";
+ width: 2rem;
+ height: 2rem;
+ line-height: 2rem;
+ font-size: 1.8rem;
+ opacity: 0.5;
+}
+
+#statusbar-network {
+ position: relative;
+}
+
+#statusbar-network::before {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 2rem;
+ height: 2rem;
+ line-height: 2rem;
+ font-size: 1.8rem;
+}
+
+#statusbar-network::after {
+ content: 'wifi-4';
+ position: absolute;
+ left: 0;
+ top: 0;
+ font-family: "openorchid-icons";
+ width: 2rem;
+ height: 2rem;
+ line-height: 2rem;
+ font-size: 1.8rem;
+ opacity: 0.5;
+}
diff --git a/style/system.css b/style/system.css
new file mode 100644
index 0000000..4d322d7
--- /dev/null
+++ b/style/system.css
@@ -0,0 +1,47 @@
+html, body {
+
+@import url('https://fonts.googleapis.com/css2?family=Readex+Pro:wght@400;500;600&display=swap');
+
+* {
+ margin: 0;
+ padding: 0;
+ font-family: "Readex Pro", sans-serif;
+}
+
+ margin: 0;
+ padding: 0;
+ font-size: 10px;
+ -webkit-tap-highlight-color: transparent;
+}
+
+#screen {
+ --statusbar-height: 4rem;
+ --statusbar-padding-left: 3rem;
+ --statusbar-padding-right: 3rem;
+ --software-buttons-height: 4rem;
+ --screen-radius: 3.6rem;
+ --chrome-toolbar-gap: 0.5rem;
+ --chrome-tablist-height: 4rem;
+ --chrome-navbar-height: 4rem;
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(to bottom, #00240c, rgb(0, 26, 42)) , url(/resources/wallpapers/default.png) no-repeat center / cover;
+
+}
+
+#screen ::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+#screen ::-webkit-scrollbar-thumb {
+ background-color: #858585;
+ background-clip: content-box;
+ border: 2px solid transparent;
+ border-radius: 8px;
+ width: 8px;
+ height: 8px;
+}
diff --git a/style/things/buttons.css b/style/things/buttons.css
new file mode 100644
index 0000000..e03126b
--- /dev/null
+++ b/style/things/buttons.css
@@ -0,0 +1,34 @@
+.ripple-button {
+ position: relative;
+ overflow: hidden;
+ display: inline-block;
+ cursor: pointer;
+}
+
+.ripple {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 0;
+ height: 0;
+ background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0.2), transparent 75%);
+ border-radius: 50%;
+ pointer-events: none;
+}
+
+.ripple.animate {
+ animation: rippleEffect 0.75s ease forwards;
+}
+
+@keyframes rippleEffect {
+ 0% {
+ opacity: 1;
+ transform: scale(0);
+ }
+ 100% {
+ opacity: 0;
+ transform: scale(1);
+ }
+}
diff --git a/style/things/fonts.css b/style/things/fonts.css
new file mode 100644
index 0000000..5f61b22
--- /dev/null
+++ b/style/things/fonts.css
@@ -0,0 +1,51 @@
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-ExtraLight.ttf);
+ font-weight: 200;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Light.ttf);
+ font-weight: 300;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Regular.ttf);
+ font-weight: 400;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Medium.ttf);
+ font-weight: 500;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-SemiBold.ttf);
+ font-weight: 600;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Bold.ttf);
+ font-weight: 700;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-ExtraBold.ttf);
+ font-weight: 800;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Black.ttf);
+ font-weight: 900;
+}
+
+*, ::placeholder {
+ font-family: 'Jali Arabic';
+}
diff --git a/style/things/headerbars.css b/style/things/headerbars.css
new file mode 100644
index 0000000..9c2710c
--- /dev/null
+++ b/style/things/headerbars.css
@@ -0,0 +1,79 @@
+.headerbar {
+ width: 100%;
+ height: calc(var(--statusbar-height) + 5rem + (4rem * (1 - var(--progress, 0))));
+ background-color: rgba(var(--headerbar-r), var(--headerbar-g), var(--headerbar-b), calc(var(--progress, 0) * 0.75));
+ display: flex;
+ padding: var(--statusbar-height) 1rem 0;
+ box-sizing: border-box;
+ z-index: 10;
+ flex-shrink: 0;
+ backdrop-filter: blur(20px) saturate(calc(100% + (80% * var(--progress, 0))));
+}
+
+.headerbar .safezone {
+ width: 100%;
+ max-width: 74.5rem;
+ margin: 0 auto;
+ display: flex;
+}
+
+.headerbar h1 {
+ flex-grow: 1;
+ margin: 0;
+ padding: 0 1rem;
+ box-sizing: border-box;
+ height: calc(5rem - (1rem * (1 - var(--progress, 0))));
+ line-height: calc(5rem - (1rem * (1 - var(--progress, 0))));
+ display: inline-block;
+ color: var(--text-color);
+ font-weight: normal;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ transform: translateY(calc(4.5rem * (1 - var(--progress, 0))));
+ width: 100%;
+ font-size: calc(2rem + (0.8rem * (1 - var(--progress, 0))));
+}
+
+.headerbar a + h1 {
+ transform: translate(calc(-4rem * (1 - var(--progress, 0))), calc(4.5rem * (1 - var(--progress, 0))));
+}
+
+.headerbar a {
+ width: 4rem;
+ height: 4rem;
+ text-decoration: none;
+ line-height: 4rem;
+ border-radius: 50%;
+ display: inline-block;
+ color: var(--text-color);
+ flex-shrink: 0;
+ margin: 0.5rem 0;
+ text-align: center;
+ padding: 0 1rem;
+ box-sizing: border-box;
+}
+
+.headerbar a:hover {
+ background-color: var(--item-hover);
+}
+
+.headerbar a:active {
+ background-color: var(--item-active);
+}
+
+.headerbar a[data-icon]::before {
+ width: 2rem;
+ height: 4rem;
+ line-height: 4rem;
+ font-size: 2rem;
+}
+
+.headerbar menu[role="toolbar"] {
+ display: inline-flex;
+ height: 5rem;
+ flex-shrink: 0;
+ margin: 0;
+ padding: 0;
+ /* transform: translate(0, calc(50% * (1 - var(--progress, 0)))); */
+}
diff --git a/style/things/icons/fonts/openorchid-icons.eot b/style/things/icons/fonts/openorchid-icons.eot
new file mode 100644
index 0000000..92675a1
Binary files /dev/null and b/style/things/icons/fonts/openorchid-icons.eot differ
diff --git a/style/things/icons/fonts/openorchid-icons.svg b/style/things/icons/fonts/openorchid-icons.svg
new file mode 100644
index 0000000..5a9e7a0
--- /dev/null
+++ b/style/things/icons/fonts/openorchid-icons.svg
@@ -0,0 +1,959 @@
+
+
+
\ No newline at end of file
diff --git a/style/things/icons/fonts/openorchid-icons.ttf b/style/things/icons/fonts/openorchid-icons.ttf
new file mode 100644
index 0000000..666be18
Binary files /dev/null and b/style/things/icons/fonts/openorchid-icons.ttf differ
diff --git a/style/things/icons/fonts/openorchid-icons.woff b/style/things/icons/fonts/openorchid-icons.woff
new file mode 100644
index 0000000..c516071
Binary files /dev/null and b/style/things/icons/fonts/openorchid-icons.woff differ
diff --git a/style/things/icons/icons.css b/style/things/icons/icons.css
new file mode 100644
index 0000000..a369788
--- /dev/null
+++ b/style/things/icons/icons.css
@@ -0,0 +1,1454 @@
+/* Generated by grunt-webfont */
+/* Based on https://github.com/endtwist/fontcustom/blob/master/lib/fontcustom/templates/fontcustom.css */
+
+
+@font-face {
+ font-family: "openorchid-icons";
+ src: url('fonts/openorchid-icons.eot');
+ src: url('fonts/openorchid-icons.eot') format('embedded-opentype'),
+ url('fonts/openorchid-icons.ttf') format('truetype'),
+ url('fonts/openorchid-icons.woff') format('woff'),
+ url('fonts/openorchid-icons.svg#openorchid-icons') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ font-display: block;
+}
+
+
+[data-icon]:before,
+.ligature-icons {
+ font-family: "openorchid-icons";
+ content: attr(data-icon);
+ display: inline-block;
+ font-weight: 500;
+ font-style: normal;
+ text-decoration: inherit;
+ text-transform: none;
+ text-rendering: optimizeLegibility;
+ font-size: 30px;
+ -webkit-font-smoothing: antialiased;
+}
+
+
+.icon-accessibility:before {
+ content: "\e900";
+}
+.icon-achievement:before {
+ content: "\e901";
+}
+.icon-activecall-bluetooth:before {
+ content: "\e902";
+}
+.icon-activecall-hangup:before {
+ content: "\e903";
+}
+.icon-activecall-hold:before {
+ content: "\e904";
+}
+.icon-activecall-mergecalls:before {
+ content: "\e905";
+}
+.icon-activecall-mute:before {
+ content: "\e906";
+}
+.icon-activecall-pickup:before {
+ content: "\e907";
+}
+.icon-activecall-sms:before {
+ content: "\e908";
+}
+.icon-activecall-speaker:before {
+ content: "\e909";
+}
+.icon-activecall-switchlines:before {
+ content: "\e90a";
+}
+.icon-activecall-voicemail:before {
+ content: "\e90b";
+}
+.icon-add:before {
+ content: "\e90c";
+}
+.icon-addons:before {
+ content: "\e90d";
+}
+.icon-airplane:before {
+ content: "\e90e";
+}
+.icon-alarm-clock:before {
+ content: "\e90f";
+}
+.icon-alarmstop:before {
+ content: "\e910";
+}
+.icon-album:before {
+ content: "\e911";
+}
+.icon-all-day:before {
+ content: "\e912";
+}
+.icon-apps:before {
+ content: "\e913";
+}
+.icon-artist:before {
+ content: "\e914";
+}
+.icon-attachments:before {
+ content: "\e915";
+}
+.icon-audio:before {
+ content: "\e916";
+}
+.icon-auth:before {
+ content: "\e917";
+}
+.icon-auto-enhance-spark:before {
+ content: "\e918";
+}
+.icon-back:before {
+ content: "\e91a";
+}
+.icon-back-light:before {
+ content: "\e91b";
+}
+.icon-battery:before {
+ content: "\e91c";
+}
+.icon-battery-0:before {
+ content: "\e91d";
+}
+.icon-battery-10:before {
+ content: "\e91e";
+}
+.icon-battery-100:before {
+ content: "\e927";
+}
+.icon-battery-20:before {
+ content: "\e91f";
+}
+.icon-battery-30:before {
+ content: "\e920";
+}
+.icon-battery-40:before {
+ content: "\e921";
+}
+.icon-battery-50:before {
+ content: "\e922";
+}
+.icon-battery-60:before {
+ content: "\e923";
+}
+.icon-battery-70:before {
+ content: "\e924";
+}
+.icon-battery-80:before {
+ content: "\e925";
+}
+.icon-battery-90:before {
+ content: "\e926";
+}
+.icon-battery-charging:before {
+ content: "\e928";
+}
+.icon-battery-charging-0:before {
+ content: "\e929";
+}
+.icon-battery-charging-10:before {
+ content: "\e92a";
+}
+.icon-battery-charging-100:before {
+ content: "\e933";
+}
+.icon-battery-charging-20:before {
+ content: "\e92b";
+}
+.icon-battery-charging-30:before {
+ content: "\e92c";
+}
+.icon-battery-charging-40:before {
+ content: "\e92d";
+}
+.icon-battery-charging-50:before {
+ content: "\e92e";
+}
+.icon-battery-charging-60:before {
+ content: "\e92f";
+}
+.icon-battery-charging-70:before {
+ content: "\e930";
+}
+.icon-battery-charging-80:before {
+ content: "\e931";
+}
+.icon-battery-charging-90:before {
+ content: "\e932";
+}
+.icon-bell:before {
+ content: "\e934";
+}
+.icon-bluetooth:before {
+ content: "\e935";
+}
+.icon-bookmark:before {
+ content: "\e936";
+}
+.icon-bookmarked:before {
+ content: "\e937";
+}
+.icon-brightness:before {
+ content: "\e938";
+}
+.icon-browser-back:before {
+ content: "\e939";
+}
+.icon-browser-closecancel:before {
+ content: "\e93a";
+}
+.icon-browser-crashedtab:before {
+ content: "\e93b";
+}
+.icon-browser-forward:before {
+ content: "\e93c";
+}
+.icon-browser-home:before {
+ content: "\e93d";
+}
+.icon-browser-library:before {
+ content: "\e93e";
+}
+.icon-browser-moretabs:before {
+ content: "\e93f";
+}
+.icon-browser-nofavicon:before {
+ content: "\e940";
+}
+.icon-browser-pictureinpicture:before {
+ content: "\e941";
+}
+.icon-browser-readermode:before {
+ content: "\e942";
+}
+.icon-browser-reload:before {
+ content: "\e943";
+}
+.icon-browser-search:before {
+ content: "\e944";
+}
+.icon-browser-secure:before {
+ content: "\e945";
+}
+.icon-browser-secureunverified:before {
+ content: "\e946";
+}
+.icon-browser-sidetabs:before {
+ content: "\e947";
+}
+.icon-browser-tabpreviews:before {
+ content: "\e948";
+}
+.icon-browsing:before {
+ content: "\e949";
+}
+.icon-bug:before {
+ content: "\e94a";
+}
+.icon-calendar-alarm:before {
+ content: "\e94b";
+}
+.icon-calendar-allday:before {
+ content: "\e94c";
+}
+.icon-calendar-bullet:before {
+ content: "\e94d";
+}
+.icon-calendar-dot:before {
+ content: "\e94e";
+}
+.icon-calendar-eventalarm:before {
+ content: "\e94f";
+}
+.icon-calendar-today:before {
+ content: "\e950";
+}
+.icon-call:before {
+ content: "\e951";
+}
+.icon-call-incoming:before {
+ content: "\e952";
+}
+.icon-call-outgoing:before {
+ content: "\e95c";
+}
+.icon-call-ringing:before {
+ content: "\e95d";
+}
+.icon-calllog-checkboxoff:before {
+ content: "\e953";
+}
+.icon-calllog-checkboxon-box:before {
+ content: "\e954";
+}
+.icon-calllog-checkboxon-checkmark:before {
+ content: "\e955";
+}
+.icon-calllog-expand:before {
+ content: "\e956";
+}
+.icon-calllog-incomingcall:before {
+ content: "\e957";
+}
+.icon-calllog-incomingsms:before {
+ content: "\e958";
+}
+.icon-calllog-missedcall:before {
+ content: "\e959";
+}
+.icon-calllog-outgoingcall:before {
+ content: "\e95a";
+}
+.icon-calllog-outgoingsms:before {
+ content: "\e95b";
+}
+.icon-camera:before {
+ content: "\e95e";
+}
+.icon-camera-cameraorientation:before {
+ content: "\e95f";
+}
+.icon-camera-flashauto:before {
+ content: "\e960";
+}
+.icon-camera-flashoff:before {
+ content: "\e961";
+}
+.icon-camera-flashon:before {
+ content: "\e962";
+}
+.icon-camera-videorecorder:before {
+ content: "\e963";
+}
+.icon-change-wallpaper:before {
+ content: "\e964";
+}
+.icon-checked:before {
+ content: "\e965";
+}
+.icon-clear-all:before {
+ content: "\e966";
+}
+.icon-clearcancel-circle:before {
+ content: "\e967";
+}
+.icon-clearcancel-cross:before {
+ content: "\e968";
+}
+.icon-close:before {
+ content: "\e969";
+}
+.icon-closecancel:before {
+ content: "\e96a";
+}
+.icon-collapse-chevron:before {
+ content: "\e96b";
+}
+.icon-compose:before {
+ content: "\e96c";
+}
+.icon-contact-add:before {
+ content: "\e96d";
+}
+.icon-contact-addfavorite:before {
+ content: "\e96e";
+}
+.icon-contact-addimage:before {
+ content: "\e96f";
+}
+.icon-contact-checkmark:before {
+ content: "\e970";
+}
+.icon-contact-delete-circle:before {
+ content: "\e971";
+}
+.icon-contact-delete-minus:before {
+ content: "\e972";
+}
+.icon-contact-detailfacebook-f:before {
+ content: "\e973";
+}
+.icon-contact-detailfacebook-square:before {
+ content: "\e974";
+}
+.icon-contact-email:before {
+ content: "\e975";
+}
+.icon-contact-favorite:before {
+ content: "\e976";
+}
+.icon-contact-favorited:before {
+ content: "\e977";
+}
+.icon-contact-favoritedcontact:before {
+ content: "\e978";
+}
+.icon-contact-find:before {
+ content: "\e979";
+}
+.icon-contact-link:before {
+ content: "\e97a";
+}
+.icon-contact-location:before {
+ content: "\e97b";
+}
+.icon-contact-phone:before {
+ content: "\e97c";
+}
+.icon-contact-sms:before {
+ content: "\e97e";
+}
+.icon-contact-twitter:before {
+ content: "\e97f";
+}
+.icon-contact-undo-roundarrow:before {
+ content: "\e981";
+}
+.icon-contacts:before {
+ content: "\e97d";
+}
+.icon-copy:before {
+ content: "\e982";
+}
+.icon-costcontrol-topup:before {
+ content: "\e983";
+}
+.icon-costcontrol-topuppay:before {
+ content: "\e984";
+}
+.icon-costcontrol-topupwithcode:before {
+ content: "\e985";
+}
+.icon-costcontrol-updatebalance:before {
+ content: "\e986";
+}
+.icon-crop:before {
+ content: "\e987";
+}
+.icon-cut:before {
+ content: "\e988";
+}
+.icon-data:before {
+ content: "\e989";
+}
+.icon-database:before {
+ content: "\e98a";
+}
+.icon-delete:before {
+ content: "\e98b";
+}
+.icon-desktop:before {
+ content: "\e98c";
+}
+.icon-developer:before {
+ content: "\e98d";
+}
+.icon-dialer-contacts:before {
+ content: "\e98e";
+}
+.icon-dialer-delete:before {
+ content: "\e98f";
+}
+.icon-dialer-dialpad:before {
+ content: "\e990";
+}
+.icon-dialer-recentcalls:before {
+ content: "\e991";
+}
+.icon-dialpad:before {
+ content: "\e992";
+}
+.icon-discord:before {
+ content: "\e993";
+}
+.icon-dislike:before {
+ content: "\e994";
+}
+.icon-disliked:before {
+ content: "\e995";
+}
+.icon-dismisskeyboard:before {
+ content: "\e996";
+}
+.icon-display:before {
+ content: "\e997";
+}
+.icon-do-not-track:before {
+ content: "\e998";
+}
+.icon-download:before {
+ content: "\e999";
+}
+.icon-download-circle:before {
+ content: "\e99a";
+}
+.icon-edit:before {
+ content: "\e99b";
+}
+.icon-edit-image:before {
+ content: "\e99d";
+}
+.icon-editcontact:before {
+ content: "\e99c";
+}
+.icon-eject:before {
+ content: "\e99e";
+}
+.icon-email:before {
+ content: "\e99f";
+}
+.icon-email-addrecipient-circle:before {
+ content: "\e9a0";
+}
+.icon-email-addrecipient-plus:before {
+ content: "\e9a1";
+}
+.icon-email-attachment:before {
+ content: "\e9a2";
+}
+.icon-email-downloadattachment:before {
+ content: "\e9a3";
+}
+.icon-email-flag:before {
+ content: "\e9a4";
+}
+.icon-email-forward:before {
+ content: "\e9a5";
+}
+.icon-email-markread:before {
+ content: "\e9a6";
+}
+.icon-email-markunread:before {
+ content: "\e9a7";
+}
+.icon-email-move:before {
+ content: "\e9a8";
+}
+.icon-email-removeattachment-circle:before {
+ content: "\e9a9";
+}
+.icon-email-removeattachment-cross:before {
+ content: "\e9aa";
+}
+.icon-email-reply:before {
+ content: "\e9ab";
+}
+.icon-email-replyall:before {
+ content: "\e9ac";
+}
+.icon-email-send:before {
+ content: "\e9ad";
+}
+.icon-emailsmscalilog-editlist:before {
+ content: "\e9ae";
+}
+.icon-emojis:before {
+ content: "\e9af";
+}
+.icon-eraser:before {
+ content: "\e9b0";
+}
+.icon-expand:before {
+ content: "\e9b1";
+}
+.icon-expand-chevron:before {
+ content: "\e9b2";
+}
+.icon-export:before {
+ content: "\e9b3";
+}
+.icon-face-recognition:before {
+ content: "\e9b5";
+}
+.icon-face-recognition-fail:before {
+ content: "\e9b6";
+}
+.icon-facebook:before {
+ content: "\e9b4";
+}
+.icon-favorites:before {
+ content: "\e9b7";
+}
+.icon-feedback:before {
+ content: "\e9b8";
+}
+.icon-file:before {
+ content: "\e9b9";
+}
+.icon-find:before {
+ content: "\e9ba";
+}
+.icon-fingerprint:before {
+ content: "\e9bb";
+}
+.icon-firefox:before {
+ content: "\e9bc";
+}
+.icon-flag:before {
+ content: "\e9bd";
+}
+.icon-flashlight:before {
+ content: "\e9be";
+}
+.icon-fm-favouritedstation:before {
+ content: "\e9bf";
+}
+.icon-fm-sound:before {
+ content: "\e9c0";
+}
+.icon-folder:before {
+ content: "\e9c1";
+}
+.icon-forbidden:before {
+ content: "\e9c2";
+}
+.icon-forward:before {
+ content: "\e9c3";
+}
+.icon-forward-light:before {
+ content: "\e9c4";
+}
+.icon-ftu-importgmail:before {
+ content: "\e9c5";
+}
+.icon-ftu-importoutlook:before {
+ content: "\e9c6";
+}
+.icon-ftu-importsdcard:before {
+ content: "\e9c7";
+}
+.icon-ftu-importsim:before {
+ content: "\e9c8";
+}
+.icon-fullscreen:before {
+ content: "\e9c9";
+}
+.icon-fullscreen-exit:before {
+ content: "\e9ca";
+}
+.icon-gallery-autoenhancespark:before {
+ content: "\e9cb";
+}
+.icon-gallery-crop:before {
+ content: "\e9cd";
+}
+.icon-gallery-crop-photo:before {
+ content: "\e9d2";
+}
+.icon-gallery-crop1x1-mark:before {
+ content: "\e9ce";
+}
+.icon-gallery-crop2x3-mark:before {
+ content: "\e9cf";
+}
+.icon-gallery-crop3x2-mark:before {
+ content: "\e9d0";
+}
+.icon-gallery-cropfree-mark:before {
+ content: "\e9d1";
+}
+.icon-gallery-exposure:before {
+ content: "\e9d3";
+}
+.icon-gallery-filterscircleopacity100:before {
+ content: "\e9d6";
+}
+.icon-gallery-filterscircleopacity35:before {
+ content: "\e9d4";
+}
+.icon-gallery-filterscircleopacity50:before {
+ content: "\e9d5";
+}
+.icon-gallery-rotate:before {
+ content: "\e9d7";
+}
+.icon-game:before {
+ content: "\e9d8";
+}
+.icon-gerneral-unlock:before {
+ content: "\e9d9";
+}
+.icon-gesture:before {
+ content: "\e9da";
+}
+.icon-gmail:before {
+ content: "\e9db";
+}
+.icon-google:before {
+ content: "\e9dc";
+}
+.icon-grid:before {
+ content: "\e9dd";
+}
+.icon-heart:before {
+ content: "\e9de";
+}
+.icon-help:before {
+ content: "\e9df";
+}
+.icon-history:before {
+ content: "\e9e0";
+}
+.icon-home:before {
+ content: "\e9e1";
+}
+.icon-homescreen:before {
+ content: "\e9e2";
+}
+.icon-homescreendelete-circle:before {
+ content: "\e9e3";
+}
+.icon-homescreendelete-cross:before {
+ content: "\e9e4";
+}
+.icon-info:before {
+ content: "\e9e5";
+}
+.icon-instagram:before {
+ content: "\e9e6";
+}
+.icon-iris-scanner:before {
+ content: "\e9e7";
+}
+.icon-iris-scanner-fail:before {
+ content: "\e9e8";
+}
+.icon-iris-scanner-success:before {
+ content: "\e9e9";
+}
+.icon-keyboard:before {
+ content: "\e9ea";
+}
+.icon-keyboard-circle:before {
+ content: "\e9eb";
+}
+.icon-languages:before {
+ content: "\e9ec";
+}
+.icon-left:before {
+ content: "\e9ed";
+}
+.icon-left-light:before {
+ content: "\e9ee";
+}
+.icon-library:before {
+ content: "\e9ef";
+}
+.icon-like:before {
+ content: "\e9f0";
+}
+.icon-liked:before {
+ content: "\e9f1";
+}
+.icon-link:before {
+ content: "\e9f2";
+}
+.icon-linkedin:before {
+ content: "\e9f3";
+}
+.icon-location:before {
+ content: "\e9f4";
+}
+.icon-lock:before {
+ content: "\e9f5";
+}
+.icon-logout:before {
+ content: "\e9f6";
+}
+.icon-media-camera:before {
+ content: "\e9f7";
+}
+.icon-media-info:before {
+ content: "\e9f8";
+}
+.icon-media-pause:before {
+ content: "\e9f9";
+}
+.icon-media-play:before {
+ content: "\e9fa";
+}
+.icon-media-playcircle:before {
+ content: "\e9fb";
+}
+.icon-media-repeatinfinite:before {
+ content: "\e9fc";
+}
+.icon-media-repeatonce:before {
+ content: "\e9fd";
+}
+.icon-media-seekbackward:before {
+ content: "\e9fe";
+}
+.icon-media-seekforward:before {
+ content: "\e9ff";
+}
+.icon-media-shuffle:before {
+ content: "\ea00";
+}
+.icon-media-skipbackward:before {
+ content: "\ea01";
+}
+.icon-media-skipforward:before {
+ content: "\ea02";
+}
+.icon-media-songs:before {
+ content: "\ea03";
+}
+.icon-media-stop:before {
+ content: "\ea04";
+}
+.icon-media-storage:before {
+ content: "\ea05";
+}
+.icon-menu:before {
+ content: "\ea06";
+}
+.icon-messages:before {
+ content: "\ea07";
+}
+.icon-mic:before {
+ content: "\ea08";
+}
+.icon-miscellaneous-editimage:before {
+ content: "\ea09";
+}
+.icon-miscellaneous-select:before {
+ content: "\ea0a";
+}
+.icon-miscellaneous-undo:before {
+ content: "\ea0b";
+}
+.icon-moderator:before {
+ content: "\ea0c";
+}
+.icon-moon:before {
+ content: "\ea0d";
+}
+.icon-more:before {
+ content: "\ea0e";
+}
+.icon-music-album:before {
+ content: "\ea0f";
+}
+.icon-music-artist:before {
+ content: "\ea10";
+}
+.icon-music-gridview:before {
+ content: "\ea11";
+}
+.icon-music-playlist:before {
+ content: "\ea12";
+}
+.icon-newadd:before {
+ content: "\ea13";
+}
+.icon-nfc:before {
+ content: "\ea14";
+}
+.icon-notification-bluetooth:before {
+ content: "\ea15";
+}
+.icon-notification-bluetoothtransfer:before {
+ content: "\ea16";
+}
+.icon-notification-cameramic:before {
+ content: "\ea17";
+}
+.icon-notification-cameraon:before {
+ content: "\ea18";
+}
+.icon-notification-circle:before {
+ content: "\ea19";
+}
+.icon-notification-download:before {
+ content: "\ea1a";
+}
+.icon-notification-downloadfailed-exclamation:before {
+ content: "\ea1b";
+}
+.icon-notification-facebook:before {
+ content: "\ea1c";
+}
+.icon-notification-importingfrommemorycard:before {
+ content: "\ea1d";
+}
+.icon-notification-lowstorage:before {
+ content: "\ea1e";
+}
+.icon-notification-mic:before {
+ content: "\ea1f";
+}
+.icon-notifications:before {
+ content: "\ea20";
+}
+.icon-options:before {
+ content: "\ea21";
+}
+.icon-outlook:before {
+ content: "\ea22";
+}
+.icon-paintbrush:before {
+ content: "\ea23";
+}
+.icon-paintbucket:before {
+ content: "\ea24";
+}
+.icon-paste:before {
+ content: "\ea25";
+}
+.icon-pause:before {
+ content: "\ea26";
+}
+.icon-permissions:before {
+ content: "\ea27";
+}
+.icon-phone:before {
+ content: "\ea28";
+}
+.icon-picture-in-picture:before {
+ content: "\ea29";
+}
+.icon-pin:before {
+ content: "\ea2a";
+}
+.icon-play:before {
+ content: "\ea2b";
+}
+.icon-play-circle:before {
+ content: "\ea2c";
+}
+.icon-playlist:before {
+ content: "\ea2d";
+}
+.icon-power:before {
+ content: "\ea2e";
+}
+.icon-qr:before {
+ content: "\ea2f";
+}
+.icon-qr-scan:before {
+ content: "\ea30";
+}
+.icon-quote:before {
+ content: "\ea31";
+}
+.icon-reader-mode:before {
+ content: "\ea32";
+}
+.icon-recent-calls:before {
+ content: "\ea33";
+}
+.icon-redo:before {
+ content: "\ea34";
+}
+.icon-reload:before {
+ content: "\ea35";
+}
+.icon-repeat:before {
+ content: "\ea36";
+}
+.icon-repeat-once:before {
+ content: "\ea37";
+}
+.icon-right:before {
+ content: "\ea38";
+}
+.icon-right-light:before {
+ content: "\ea39";
+}
+.icon-save:before {
+ content: "\ea3a";
+}
+.icon-sdcard:before {
+ content: "\ea3b";
+}
+.icon-search:before {
+ content: "\ea3c";
+}
+.icon-select:before {
+ content: "\ea3d";
+}
+.icon-selectall:before {
+ content: "\ea3e";
+}
+.icon-send:before {
+ content: "\ea3f";
+}
+.icon-settings:before {
+ content: "\ea40";
+}
+.icon-settings-aboutphone:before {
+ content: "\ea41";
+}
+.icon-settings-accessibility:before {
+ content: "\ea42";
+}
+.icon-settings-airplane:before {
+ content: "\ea43";
+}
+.icon-settings-app-permissions:before {
+ content: "\ea44";
+}
+.icon-settings-apps:before {
+ content: "\ea45";
+}
+.icon-settings-appstorage:before {
+ content: "\ea46";
+}
+.icon-settings-battery:before {
+ content: "\ea47";
+}
+.icon-settings-bluetooth:before {
+ content: "\ea48";
+}
+.icon-settings-brightness:before {
+ content: "\ea49";
+}
+.icon-settings-brightness-lower:before {
+ content: "\ea4a";
+}
+.icon-settings-call:before {
+ content: "\ea4b";
+}
+.icon-settings-camera-permissions:before {
+ content: "\ea4c";
+}
+.icon-settings-changewallpapericon:before {
+ content: "\ea4e";
+}
+.icon-settings-contacts-permissions:before {
+ content: "\ea4f";
+}
+.icon-settings-developer:before {
+ content: "\ea50";
+}
+.icon-settings-deviceinfo:before {
+ content: "\ea51";
+}
+.icon-settings-devicestorage-permissions:before {
+ content: "\ea52";
+}
+.icon-settings-display:before {
+ content: "\ea53";
+}
+.icon-settings-donottrack:before {
+ content: "\ea54";
+}
+.icon-settings-download:before {
+ content: "\ea55";
+}
+.icon-settings-email:before {
+ content: "\ea56";
+}
+.icon-settings-facerecognition:before {
+ content: "\ea57";
+}
+.icon-settings-feedback:before {
+ content: "\ea58";
+}
+.icon-settings-findmydevice:before {
+ content: "\ea59";
+}
+.icon-settings-fingerprint:before {
+ content: "\ea5a";
+}
+.icon-settings-fmradio-permissions:before {
+ content: "\ea5b";
+}
+.icon-settings-gesture:before {
+ content: "\ea5c";
+}
+.icon-settings-gps:before {
+ content: "\ea5d";
+}
+.icon-settings-gps-permissions:before {
+ content: "\ea5e";
+}
+.icon-settings-help:before {
+ content: "\ea5f";
+}
+.icon-settings-helpx:before {
+ content: "\ea60";
+}
+.icon-settings-homescreen:before {
+ content: "\ea61";
+}
+.icon-settings-irisscanner:before {
+ content: "\ea62";
+}
+.icon-settings-languages:before {
+ content: "\ea63";
+}
+.icon-settings-mediastorage:before {
+ content: "\ea64";
+}
+.icon-settings-messages:before {
+ content: "\ea65";
+}
+.icon-settings-network:before {
+ content: "\ea66";
+}
+.icon-settings-nfc:before {
+ content: "\ea67";
+}
+.icon-settings-notifications:before {
+ content: "\ea68";
+}
+.icon-settings-persona:before {
+ content: "\ea69";
+}
+.icon-settings-phonelock:before {
+ content: "\ea6a";
+}
+.icon-settings-privacy:before {
+ content: "\ea6b";
+}
+.icon-settings-simcardlock:before {
+ content: "\ea6c";
+}
+.icon-settings-simtoolkit:before {
+ content: "\ea6d";
+}
+.icon-settings-sound-max:before {
+ content: "\ea6e";
+}
+.icon-settings-sound-min:before {
+ content: "\ea6f";
+}
+.icon-settings-tethering:before {
+ content: "\ea70";
+}
+.icon-settings-themes:before {
+ content: "\ea71";
+}
+.icon-settings-time:before {
+ content: "\ea72";
+}
+.icon-settings-usbstorage:before {
+ content: "\ea73";
+}
+.icon-settings-wallpaper:before {
+ content: "\ea74";
+}
+.icon-settings-wifi:before {
+ content: "\ea75";
+}
+.icon-settings-wifi-1:before {
+ content: "\ea76";
+}
+.icon-settings-wifi-2:before {
+ content: "\ea77";
+}
+.icon-settings-wifi-3:before {
+ content: "\ea78";
+}
+.icon-settings-wifi-4:before {
+ content: "\ea79";
+}
+.icon-settings-wifi-lock:before {
+ content: "\ea7a";
+}
+.icon-settings-wifi-lock-1:before {
+ content: "\ea7b";
+}
+.icon-settings-wifi-lock-2:before {
+ content: "\ea7c";
+}
+.icon-settings-wifi-lock-3:before {
+ content: "\ea7d";
+}
+.icon-settings-wifi-lock-4:before {
+ content: "\ea7e";
+}
+.icon-settings-wifi-permissions:before {
+ content: "\ea7f";
+}
+.icon-share:before {
+ content: "\ea80";
+}
+.icon-shopping-cart:before {
+ content: "\ea81";
+}
+.icon-shuffle:before {
+ content: "\ea82";
+}
+.icon-side-tabs:before {
+ content: "\ea83";
+}
+.icon-signal-1:before {
+ content: "\ea84";
+}
+.icon-signal-2:before {
+ content: "\ea85";
+}
+.icon-signal-3:before {
+ content: "\ea86";
+}
+.icon-signal-4:before {
+ content: "\ea87";
+}
+.icon-signal-5:before {
+ content: "\ea88";
+}
+.icon-sim:before {
+ content: "\ea89";
+}
+.icon-skip-back:before {
+ content: "\ea8a";
+}
+.icon-skip-forward:before {
+ content: "\ea8b";
+}
+.icon-sms:before {
+ content: "\ea8c";
+}
+.icon-snap-bottom:before {
+ content: "\ea8d";
+}
+.icon-snap-bottom-left:before {
+ content: "\ea8e";
+}
+.icon-snap-bottom-right:before {
+ content: "\ea8f";
+}
+.icon-snap-left:before {
+ content: "\ea90";
+}
+.icon-snap-right:before {
+ content: "\ea91";
+}
+.icon-snap-top:before {
+ content: "\ea92";
+}
+.icon-snap-top-left:before {
+ content: "\ea93";
+}
+.icon-snap-top-right:before {
+ content: "\ea94";
+}
+.icon-songs:before {
+ content: "\ea95";
+}
+.icon-sound-max:before {
+ content: "\ea96";
+}
+.icon-sound-min:before {
+ content: "\ea97";
+}
+.icon-speaker:before {
+ content: "\ea98";
+}
+.icon-splitscreen:before {
+ content: "\ea99";
+}
+.icon-spotify-svgrepo-com:before {
+ content: "\ea9a";
+}
+.icon-ssl:before {
+ content: "\ea9b";
+}
+.icon-ssl-broken:before {
+ content: "\ea9c";
+}
+.icon-stickers:before {
+ content: "\ea9d";
+}
+.icon-storage:before {
+ content: "\ea9e";
+}
+.icon-sync:before {
+ content: "\ea9f";
+}
+.icon-tab-previews:before {
+ content: "\eaa1";
+}
+.icon-tablet:before {
+ content: "\eaa0";
+}
+.icon-taskswitcherappclose-circle:before {
+ content: "\eaa2";
+}
+.icon-taskswitcherappclose-cross:before {
+ content: "\eaa3";
+}
+.icon-television:before {
+ content: "\eaa4";
+}
+.icon-tethering:before {
+ content: "\eaa5";
+}
+.icon-textselection-copy:before {
+ content: "\eaa6";
+}
+.icon-textselection-cut:before {
+ content: "\eaa7";
+}
+.icon-textselection-paste:before {
+ content: "\eaa8";
+}
+.icon-textselection-selectall:before {
+ content: "\eaa9";
+}
+.icon-themes:before {
+ content: "\eaaa";
+}
+.icon-threadnotsent-circle:before {
+ content: "\eaab";
+}
+.icon-threadnotsent-exclamation:before {
+ content: "\eaac";
+}
+.icon-tick:before {
+ content: "\eaad";
+}
+.icon-tick-circle:before {
+ content: "\eaae";
+}
+.icon-tiktok:before {
+ content: "\eaaf";
+}
+.icon-time:before {
+ content: "\eab0";
+}
+.icon-treadsent-check:before {
+ content: "\eab1";
+}
+.icon-treadsent-circle:before {
+ content: "\eab2";
+}
+.icon-tree:before {
+ content: "\eab3";
+}
+.icon-tv:before {
+ content: "\eab4";
+}
+.icon-twitch:before {
+ content: "\eab5";
+}
+.icon-twitter:before {
+ content: "\eab6";
+}
+.icon-undo:before {
+ content: "\eab7";
+}
+.icon-upload:before {
+ content: "\eab8";
+}
+.icon-usb:before {
+ content: "\eab9";
+}
+.icon-user:before {
+ content: "\eaba";
+}
+.icon-useraccoun-headers:before {
+ content: "\eabb";
+}
+.icon-utility-airplanemode:before {
+ content: "\eabc";
+}
+.icon-utility-arrow:before {
+ content: "\eabd";
+}
+.icon-utility-battery:before {
+ content: "\eabe";
+}
+.icon-utility-bluetooth:before {
+ content: "\eabf";
+}
+.icon-utility-brightness:before {
+ content: "\eac0";
+}
+.icon-utility-camera-lockedscreen:before {
+ content: "\eac1";
+}
+.icon-utility-data:before {
+ content: "\eac2";
+}
+.icon-utility-flashlight:before {
+ content: "\eac3";
+}
+.icon-utility-maxvolume:before {
+ content: "\eac4";
+}
+.icon-utility-mute-cease:before {
+ content: "\eac5";
+}
+.icon-utility-mute-speaker:before {
+ content: "\eac6";
+}
+.icon-utility-vibrate:before {
+ content: "\eac7";
+}
+.icon-utility-volume:before {
+ content: "\eac8";
+}
+.icon-utility-wifi:before {
+ content: "\eac9";
+}
+.icon-vibrate:before {
+ content: "\eaca";
+}
+.icon-video:before {
+ content: "\eacb";
+}
+.icon-vpn:before {
+ content: "\eacc";
+}
+.icon-wallpaper:before {
+ content: "\eacd";
+}
+.icon-web:before {
+ content: "\eace";
+}
+.icon-wifi:before {
+ content: "\eacf";
+}
+.icon-wifi-1:before {
+ content: "\ead0";
+}
+.icon-wifi-2:before {
+ content: "\ead1";
+}
+.icon-wifi-3:before {
+ content: "\ead2";
+}
+.icon-wifi-4:before {
+ content: "\ead3";
+}
+.icon-windows:before {
+ content: "\ead4";
+}
+.icon-wm-snapbottom:before {
+ content: "\ead5";
+}
+.icon-wm-snapbottomleft:before {
+ content: "\ead6";
+}
+.icon-wm-snapbottomright:before {
+ content: "\ead7";
+}
+.icon-wm-snapleft:before {
+ content: "\ead8";
+}
+.icon-wm-snapright:before {
+ content: "\ead9";
+}
+.icon-wm-snaptop:before {
+ content: "\eada";
+}
+.icon-wm-snaptopleft:before {
+ content: "\eadb";
+}
+.icon-wm-snaptopright:before {
+ content: "\eadc";
+}
+.icon-youtube:before {
+ content: "\eadd";
+}
diff --git a/style/things/lists.css b/style/things/lists.css
new file mode 100644
index 0000000..eb62410
--- /dev/null
+++ b/style/things/lists.css
@@ -0,0 +1,122 @@
+.lists header {
+ width: 100%;
+ max-width: 74.8rem;
+ padding: 0 2rem;
+ box-sizing: border-box;
+ height: 3rem;
+ line-height: 3rem;
+ color: #858585;
+ font-size: 1.6rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin: 1rem auto 0;
+}
+
+.lists ul {
+ margin: 0 auto 1.5rem;
+ padding: 0.5rem;
+ background-color: var(--background-plus);
+ border-radius: 1.5rem;
+ width: calc(100% - 3rem);
+ max-width: 71.8rem;
+ box-sizing: border-box;
+}
+
+.lists ul li {
+ position: relative;
+ margin: 0;
+ list-style: none;
+ min-height: 5rem;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ width: 100%;
+ padding: 0 1.5rem;
+ box-sizing: border-box;
+ border-radius: 1rem;
+ color: var(--text-color);
+}
+
+.lists ul li:hover {
+ background-color: var(--item-hover);
+}
+
+.lists ul li:active {
+ background-color: var(--item-active);
+}
+
+.lists ul li.selected {
+ background-color: var(--accent-color);
+ color: var(--accent-color-plus);
+}
+
+.lists ul li[data-icon] {
+ padding-inline-start: 4.5rem;
+}
+
+.lists ul li[data-icon]::before {
+ position: absolute;
+ top: 50%;
+ margin-top: -1.2rem;
+ left: 1.2rem;
+ color: var(--text-color);
+ width: 2.4rem;
+ height: 2.4rem;
+ line-height: 2.4rem;
+ font-size: 2.4rem;
+}
+
+.lists ul li.selected[data-icon]::before {
+ color: var(--accent-color-plus);
+}
+
+.lists ul li.page::after {
+ content: 'forward';
+ font-family: "openorchid-icons";
+ font-size: 2rem;
+ color: #858585;
+ text-align: end;
+ line-height: 5rem;
+}
+
+.lists ul li.page.selected::after {
+ color: var(--accent-color-plus);
+ opacity: 0.5;
+}
+
+.lists ul li::after {
+ content: '';
+ position: absolute;
+ left: 1.5rem;
+ top: 0;
+ width: calc(100% - 3rem);
+ height: 100%;
+ pointer-events: none;
+ border-bottom: solid 0.1rem var(--item-hover);
+ box-sizing: border-box;
+}
+
+.lists ul li:hover::after,
+.lists ul li:active::after,
+.lists ul li:last-child::after {
+ border-bottom: none;
+}
+
+.lists ul li p {
+ margin: 0;
+ height: 2.2rem;
+ line-height: 2.2rem;
+ font-size: 1.6rem;
+ color: var(--text-color);
+}
+
+.lists ul li.selected p {
+ color: var(--accent-color-plus);
+}
+
+.lists ul li p:not(:first-child) {
+ height: 1.9rem;
+ line-height: 1.9rem;
+ font-size: 1.4rem;
+ opacity: 0.5;
+}
diff --git a/style/things/main.css b/style/things/main.css
new file mode 100644
index 0000000..e2c8636
--- /dev/null
+++ b/style/things/main.css
@@ -0,0 +1,15 @@
+html, body {
+ margin: 0;
+ padding: 0;
+ font-size: 10px;
+}
+
+.app {
+ --statusbar-height: 4rem;
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--background);
+}
diff --git a/style/things/panels.css b/style/things/panels.css
new file mode 100644
index 0000000..b05a798
--- /dev/null
+++ b/style/things/panels.css
@@ -0,0 +1,100 @@
+.panel {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--background);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ z-index: 50;
+}
+
+.panel > .content {
+ width: 100%;
+ height: 100%;
+ flex-grow: 1;
+ overflow-y: auto;
+ margin-top: calc((-5rem - var(--statusbar-height)) * var(--progress, 0));
+ scrollbar-width: none;
+}
+
+.panel > .content aside {
+ margin: 0 auto 1.5rem;
+ padding: 0;
+ background-color: var(--background-minus);
+ border-radius: 1.5rem;
+ width: calc(100% - 3rem);
+ max-width: 71.8rem;
+ box-sizing: border-box;
+}
+
+.panel > .content aside header {
+ width: 100%;
+ padding: 0 2rem;
+ box-sizing: border-box;
+ height: 3rem;
+ line-height: 3rem;
+ color: #858585;
+ font-size: 1.6rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin: 1rem 0 0;
+}
+
+.panel > .content aside ul {
+ margin: 0;
+ padding: 0 0.5rem 0.5rem;
+ width: 100%;
+ background-color: transparent;
+}
+
+.panel > .content aside ul li {
+ min-height: 3.2rem;
+ background-color: transparent;
+}
+
+.panel > .content aside ul li > a {
+ color: var(--accent-color);
+ width: max-content;
+ line-height: 2.2rem;
+ font-size: 1.6rem;
+ text-decoration: none;
+ transition: box-shadow 0.2s ease;
+}
+
+.panel > .content aside ul li > a:hover {
+ box-shadow: 0 0.2rem 0 var(--accent-color);
+}
+
+.panel > .content aside ul li > a:active {
+ opacity: 0.5;
+}
+
+@media screen and (min-width: 983px) {
+ .panel > .headerbar .safezone {
+ margin-inline-start: 0;
+ }
+
+ .panel > .content header,
+ .panel > .content ul {
+ margin-inline-start: 1.5rem;
+ }
+
+ .panel > .content aside {
+ position: absolute;
+ right: 0;
+ top: calc(5rem + var(--statusbar-height) + (4rem * (1 - var(--progress, 0))));
+ width: 22rem;
+ margin: calc(1.5rem * var(--progress, 0)) 1.5rem 1.5rem;
+ }
+}
+
+@media screen and (min-width: 1536px) {
+ .panel > .headerbar .safezone,
+ .panel > .content header,
+ .panel > .content ul {
+ margin-inline-start: auto;
+ }
+}
diff --git a/style/things/switches.css b/style/things/switches.css
new file mode 100644
index 0000000..be56c72
--- /dev/null
+++ b/style/things/switches.css
@@ -0,0 +1,83 @@
+.pack-switch {
+ width: 100%;
+ display: inline-flex;
+}
+
+.pack-switch > label {
+ width: 100%;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ flex-grow: 1;
+}
+
+.pack-switch > span {
+ flex-shrink: 0;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.pack-switch > span input[type="checkbox"] {
+ background-color: var(--switch-normal);
+ width: 5rem;
+ height: 2.5rem;
+ border-radius: 2.5rem;
+ border: none;
+ position: relative;
+ outline: none;
+ appearance: none;
+ transition: all 0.1s ease;
+}
+
+.pack-switch > span input[type="checkbox"]:hover {
+ background-color: var(--switch-hover);
+}
+
+.pack-switch > span input[type="checkbox"]:hover {
+ background-color: var(--switch-active);
+}
+
+.pack-switch > span input[type="checkbox"]:checked {
+ background-color: var(--accent-color);
+}
+
+.pack-switch > span input[type="checkbox"]::before {
+ content: '';
+ position: absolute;
+ left: 0.5rem;
+ top: 0.5rem;
+ width: 1.5rem;
+ height: 1.5rem;
+ background-color: var(--text-color);
+ border-radius: 1.5rem;
+ transition: all 0.3s cubic-bezier(0.2, 0, 0, 1);
+ z-index: 1;
+ pointer-events: none;
+}
+
+.pack-switch > span input[type="checkbox"]:hover::before {
+ transform: scale(1.2);
+}
+
+.pack-switch > span input[type="checkbox"]:active::before {
+ transform: scale(0.8);
+ width: 4rem;
+}
+
+.pack-switch > span input[type="checkbox"]:checked::before {
+ left: 3rem;
+ transform: scale(1);
+ background-color: var(--accent-color-plus);
+}
+
+.pack-switch > span input[type="checkbox"]:checked:hover::before {
+ transform: scale(1.2);
+}
+
+.pack-switch > span input[type="checkbox"]:checked:active::before {
+ left: 0.5rem;
+ transform: scale(0.8);
+ width: 4rem;
+}
\ No newline at end of file
diff --git a/style/things/tablists.css b/style/things/tablists.css
new file mode 100644
index 0000000..e69de29
diff --git a/style/things/theme.css b/style/things/theme.css
new file mode 100644
index 0000000..3690514
--- /dev/null
+++ b/style/things/theme.css
@@ -0,0 +1,61 @@
+:root {
+ --accent-color: #0061e0;
+ --accent-color-plus: rgba(255, 255, 255, 0.75);
+ --accent-color-hover: rgba(255, 255, 255, 0.05);
+ --accent-color-active: rgba(255, 255, 255, 0.1);
+
+ --background: #f0f6ff;
+ --background-plus: #fff;
+ --background-minus: #e0edff;
+
+ --acrylic-background: rgba(224, 237, 255, 0.5);
+ --acrylic-background-plus: rgba(255, 255, 255, 0.75);
+
+ --text-color: #333;
+
+ --item-plus: rgba(0, 0, 0, 0.05);
+ --item-hover: rgba(0, 0, 0, 0.05);
+ --item-hover-plus: rgba(0, 0, 0, 0.1);
+ --item-active: rgba(0, 0, 0, 0.1);
+ --item-active-plus: rgba(0, 0, 0, 0.15);
+
+ --headerbar-r: 224;
+ --headerbar-g: 237;
+ --headerbar-b: 255;
+
+ --switch-normal: #d0e3ff;
+ --switch-hover: #c0d9ff;
+ --switch-active: #b0d0ff;
+}
+
+@media screen and (prefers-color-scheme: dark) {
+ :root {
+ --accent-color: #80c2ff;
+ --accent-color-plus: rgba(0, 0, 0, 0.75);
+ --accent-color-hover: rgba(0, 0, 0, 0.05);
+ --accent-color-active: rgba(0, 0, 0, 0.1);
+
+ --background: #000;
+ --background-plus: #212326;
+ --background-minus: #101215;
+
+ --acrylic-background: rgba(16, 18, 21, 0.5);
+ --acrylic-background-plus: rgba(33, 35, 38, 0.75);
+
+ --text-color: #e7e7e7;
+
+ --item-plus: rgba(255, 255, 255, 0.05);
+ --item-hover: rgba(255, 255, 255, 0.05);
+ --item-hover-plus: rgba(255, 255, 255, 0.1);
+ --item-active: rgba(255, 255, 255, 0.1);
+ --item-active-plus: rgba(255, 255, 255, 0.15);
+
+ --headerbar-r: 16;
+ --headerbar-g: 18;
+ --headerbar-b: 21;
+
+ --switch-normal: #101215;
+ --switch-hover: #303235;
+ --switch-active: #404245;
+ }
+}
diff --git a/style/things/webview.css b/style/things/webview.css
new file mode 100644
index 0000000..b81fc92
--- /dev/null
+++ b/style/things/webview.css
@@ -0,0 +1,17 @@
+*, ::placeholder {
+ font-family: system-ui;
+}
+
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: #858585;
+ background-clip: content-box;
+ border: 2px solid transparent;
+ border-radius: 8px;
+ width: 8px;
+ height: 8px;
+}
diff --git a/style/utility_tray.css b/style/utility_tray.css
new file mode 100644
index 0000000..e75aef8
--- /dev/null
+++ b/style/utility_tray.css
@@ -0,0 +1,135 @@
+#utility-tray {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none;
+ z-index: 1024;
+}
+
+#utility-tray-motion {
+ background-color: var(--acrylic-background);
+ backdrop-filter: blur(50px) saturate(180%);
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow-x: auto;
+ pointer-events: all;
+ opacity: 0;
+ visibility: hidden;
+ transition: all 0.3s ease;
+}
+
+#utility-tray-motion.visible {
+ opacity: 1;
+ visibility: visible;
+}
+
+#utility-tray-motion::-webkit-scrollbar {
+ display: none;
+}
+
+.utility-tray-header {
+ width: 100%;
+ height: 5rem;
+ display: flex;
+ padding: 0 1.5rem;
+ box-sizing: border-box;
+ transition: all 0.5s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#utility-tray-motion.fade-out .utility-tray-header {
+ opacity: 0;
+ transform: scale(0.9);
+ visibility: hidden;
+}
+
+.utility-tray-header h1 {
+ width: 100%;
+ flex-grow: 1;
+ height: 5rem;
+ line-height: 5rem;
+ margin: 0;
+ font-size: 2rem;
+ font-weight: normal;
+ color: var(--text-color);
+ padding: 0 1rem;
+ box-sizing: border-box;
+}
+
+.utility-tray-header menu[role="toolbar"] {
+ height: 5rem;
+ display: flex;
+ padding: 0.5rem 0;
+ box-sizing: border-box;
+ margin: 0;
+ flex-shrink: 0;
+}
+
+.utility-tray-header menu[role="toolbar"] > a {
+ width: 4rem;
+ height: 4rem;
+ line-height: 4rem;
+ padding: 0 1rem;
+ box-sizing: border-box;
+ margin: 0;
+ color: var(--text-color);
+ text-decoration: none;
+ display: inline-block;
+ border-radius: 2rem;
+}
+
+.utility-tray-header menu[role="toolbar"] > a:hover {
+ background-color: var(--item-hover);
+}
+
+.utility-tray-header menu[role="toolbar"] > a:active {
+ background-color: var(--item-active);
+}
+
+.utility-tray-header menu[role="toolbar"] > a[data-icon]::before {
+ font-size: 2rem;
+}
+
+#control-center {
+ position: absolute;
+ left: 0;
+ top: var(--statusbar-height);
+ width: 100%;
+ height: calc(100% - var(--statusbar-height));
+ padding: 0 calc(50vw - 30rem);
+ box-sizing: border-box;
+}
+
+.control-center-row {
+ width: 100%;
+ padding: 0 1.5rem;
+ box-sizing: border-box;
+ margin: 0 0 1rem;
+ display: flex;
+ gap: 1rem;
+ transition: all 0.5s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#utility-tray-motion .control-center-row > * {
+ transition: all 0.5s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#utility-tray-motion.fade-out .control-center-row > * {
+ opacity: 0;
+ transform: scale(0.9);
+ visibility: hidden;
+}
+
+#notifications {
+ position: absolute;
+ left: 100%;
+ top: var(--statusbar-height);
+ width: 100%;
+ height: calc(100% - var(--statusbar-height));
+ padding: 0 calc(50vw - 30rem);
+ box-sizing: border-box;
+}
diff --git a/style/windows.css b/style/windows.css
new file mode 100644
index 0000000..d3c69d6
--- /dev/null
+++ b/style/windows.css
@@ -0,0 +1,112 @@
+#windows {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+}
+
+#screen.keyboard-visible #windows {
+ height: 60%;
+}
+
+.appframe {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: #000;
+ transform: translateY(100%);
+ visibility: hidden;
+}
+
+.appframe.active {
+ transform: translateY(0);
+ visibility: visible;
+}
+
+#homescreen.appframe {
+ transform: scale(1.5);
+ visibility: visible;
+ transition: transform 0.5s cubic-bezier(0.2, 0.9, 0.1, 1);
+}
+
+#homescreen.appframe.active {
+ transform: scale(1);
+}
+
+.appframe.expand {
+ border-radius: var(--screen-radius);
+ animation: expand 0.5s cubic-bezier(0.2, 0.9, 0.1, 1) forwards;
+}
+
+@keyframes expand {
+ from {
+ transform: scale(0.75);
+ opacity: 0;
+ }
+ to {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+.appframe.shrink {
+ border-radius: var(--screen-radius);
+ animation: shrink 0.3s cubic-bezier(0.8, 0.1, 0.9, 0) forwards;
+}
+
+@keyframes shrink {
+ from {
+ transform: scale(1);
+ opacity: 1;
+ }
+ to {
+ transform: scale(0.75);
+ opacity: 0;
+ }
+}
+
+.appframe.transparent {
+ background-color: transparent;
+}
+
+.appframe .chrome .browser {
+ position: absolute;
+ left: 0;
+ top: var(--statusbar-height);
+ width: 100%;
+ height: calc(100% - var(--statusbar-height) - 2.5rem);
+}
+
+.appframe .chrome.visible .browser {
+ top: calc(var(--statusbar-height) + var(--chrome-tablist-height) + var(--chrome-navbar-height) + (var(--chrome-toolbar-gap) * 2));
+ height: calc(100% - var(--statusbar-height) - var(--chrome-tablist-height) - var(--chrome-navbar-height) - (var(--chrome-toolbar-gap) * 2));
+}
+
+#screen.software-buttons-enabled .appframe .chrome .browser {
+ height: calc(100% - var(--statusbar-height) - var(--software-buttons-height));
+}
+
+#screen.software-buttons-enabled .appframe .chrome.visible .browser {
+ top: calc(var(--statusbar-height) + var(--chrome-tablist-height) + var(--chrome-navbar-height) + (var(--chrome-toolbar-gap) * 2));
+ height: calc(100% - var(--statusbar-height) - var(--software-buttons-height) - var(--chrome-tablist-height) - var(--chrome-navbar-height) - (var(--chrome-toolbar-gap) * 2));
+}
+
+.appframe.overlay .chrome .browser {
+ top: 0;
+ height: calc(100% - 2.5rem);
+}
+
+#screen.software-buttons-enabled .appframe.overlay .chrome .browser {
+ height: calc(100% - var(--software-buttons-height));
+}
+
+.appframe.immersive .chrome .browser,
+.appframe.fullscreen .chrome .browser,
+#screen.software-buttons-enabled .appframe.immersive .chrome .browser,
+#screen.software-buttons-enabled .appframe.fullscreen .chrome .browser {
+ top: 0;
+ height: 100%;
+}
diff --git a/things/buttons.css b/things/buttons.css
new file mode 100644
index 0000000..e03126b
--- /dev/null
+++ b/things/buttons.css
@@ -0,0 +1,34 @@
+.ripple-button {
+ position: relative;
+ overflow: hidden;
+ display: inline-block;
+ cursor: pointer;
+}
+
+.ripple {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 0;
+ height: 0;
+ background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0.2), transparent 75%);
+ border-radius: 50%;
+ pointer-events: none;
+}
+
+.ripple.animate {
+ animation: rippleEffect 0.75s ease forwards;
+}
+
+@keyframes rippleEffect {
+ 0% {
+ opacity: 1;
+ transform: scale(0);
+ }
+ 100% {
+ opacity: 0;
+ transform: scale(1);
+ }
+}
diff --git a/things/fonts.css b/things/fonts.css
new file mode 100644
index 0000000..5f61b22
--- /dev/null
+++ b/things/fonts.css
@@ -0,0 +1,51 @@
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-ExtraLight.ttf);
+ font-weight: 200;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Light.ttf);
+ font-weight: 300;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Regular.ttf);
+ font-weight: 400;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Medium.ttf);
+ font-weight: 500;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-SemiBold.ttf);
+ font-weight: 600;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Bold.ttf);
+ font-weight: 700;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-ExtraBold.ttf);
+ font-weight: 800;
+}
+
+@font-face {
+ font-family: 'Jali Arabic';
+ src: url(http://shared.localhost:8081/fonts/JaliArabic-Black.ttf);
+ font-weight: 900;
+}
+
+*, ::placeholder {
+ font-family: 'Jali Arabic';
+}
diff --git a/things/headerbars.css b/things/headerbars.css
new file mode 100644
index 0000000..9c2710c
--- /dev/null
+++ b/things/headerbars.css
@@ -0,0 +1,79 @@
+.headerbar {
+ width: 100%;
+ height: calc(var(--statusbar-height) + 5rem + (4rem * (1 - var(--progress, 0))));
+ background-color: rgba(var(--headerbar-r), var(--headerbar-g), var(--headerbar-b), calc(var(--progress, 0) * 0.75));
+ display: flex;
+ padding: var(--statusbar-height) 1rem 0;
+ box-sizing: border-box;
+ z-index: 10;
+ flex-shrink: 0;
+ backdrop-filter: blur(20px) saturate(calc(100% + (80% * var(--progress, 0))));
+}
+
+.headerbar .safezone {
+ width: 100%;
+ max-width: 74.5rem;
+ margin: 0 auto;
+ display: flex;
+}
+
+.headerbar h1 {
+ flex-grow: 1;
+ margin: 0;
+ padding: 0 1rem;
+ box-sizing: border-box;
+ height: calc(5rem - (1rem * (1 - var(--progress, 0))));
+ line-height: calc(5rem - (1rem * (1 - var(--progress, 0))));
+ display: inline-block;
+ color: var(--text-color);
+ font-weight: normal;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ transform: translateY(calc(4.5rem * (1 - var(--progress, 0))));
+ width: 100%;
+ font-size: calc(2rem + (0.8rem * (1 - var(--progress, 0))));
+}
+
+.headerbar a + h1 {
+ transform: translate(calc(-4rem * (1 - var(--progress, 0))), calc(4.5rem * (1 - var(--progress, 0))));
+}
+
+.headerbar a {
+ width: 4rem;
+ height: 4rem;
+ text-decoration: none;
+ line-height: 4rem;
+ border-radius: 50%;
+ display: inline-block;
+ color: var(--text-color);
+ flex-shrink: 0;
+ margin: 0.5rem 0;
+ text-align: center;
+ padding: 0 1rem;
+ box-sizing: border-box;
+}
+
+.headerbar a:hover {
+ background-color: var(--item-hover);
+}
+
+.headerbar a:active {
+ background-color: var(--item-active);
+}
+
+.headerbar a[data-icon]::before {
+ width: 2rem;
+ height: 4rem;
+ line-height: 4rem;
+ font-size: 2rem;
+}
+
+.headerbar menu[role="toolbar"] {
+ display: inline-flex;
+ height: 5rem;
+ flex-shrink: 0;
+ margin: 0;
+ padding: 0;
+ /* transform: translate(0, calc(50% * (1 - var(--progress, 0)))); */
+}
diff --git a/things/icons/fonts/openorchid-icons.eot b/things/icons/fonts/openorchid-icons.eot
new file mode 100644
index 0000000..92675a1
Binary files /dev/null and b/things/icons/fonts/openorchid-icons.eot differ
diff --git a/things/icons/fonts/openorchid-icons.svg b/things/icons/fonts/openorchid-icons.svg
new file mode 100644
index 0000000..5a9e7a0
--- /dev/null
+++ b/things/icons/fonts/openorchid-icons.svg
@@ -0,0 +1,959 @@
+
+
+
\ No newline at end of file
diff --git a/things/icons/fonts/openorchid-icons.ttf b/things/icons/fonts/openorchid-icons.ttf
new file mode 100644
index 0000000..666be18
Binary files /dev/null and b/things/icons/fonts/openorchid-icons.ttf differ
diff --git a/things/icons/fonts/openorchid-icons.woff b/things/icons/fonts/openorchid-icons.woff
new file mode 100644
index 0000000..c516071
Binary files /dev/null and b/things/icons/fonts/openorchid-icons.woff differ
diff --git a/things/icons/icons.css b/things/icons/icons.css
new file mode 100644
index 0000000..a369788
--- /dev/null
+++ b/things/icons/icons.css
@@ -0,0 +1,1454 @@
+/* Generated by grunt-webfont */
+/* Based on https://github.com/endtwist/fontcustom/blob/master/lib/fontcustom/templates/fontcustom.css */
+
+
+@font-face {
+ font-family: "openorchid-icons";
+ src: url('fonts/openorchid-icons.eot');
+ src: url('fonts/openorchid-icons.eot') format('embedded-opentype'),
+ url('fonts/openorchid-icons.ttf') format('truetype'),
+ url('fonts/openorchid-icons.woff') format('woff'),
+ url('fonts/openorchid-icons.svg#openorchid-icons') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ font-display: block;
+}
+
+
+[data-icon]:before,
+.ligature-icons {
+ font-family: "openorchid-icons";
+ content: attr(data-icon);
+ display: inline-block;
+ font-weight: 500;
+ font-style: normal;
+ text-decoration: inherit;
+ text-transform: none;
+ text-rendering: optimizeLegibility;
+ font-size: 30px;
+ -webkit-font-smoothing: antialiased;
+}
+
+
+.icon-accessibility:before {
+ content: "\e900";
+}
+.icon-achievement:before {
+ content: "\e901";
+}
+.icon-activecall-bluetooth:before {
+ content: "\e902";
+}
+.icon-activecall-hangup:before {
+ content: "\e903";
+}
+.icon-activecall-hold:before {
+ content: "\e904";
+}
+.icon-activecall-mergecalls:before {
+ content: "\e905";
+}
+.icon-activecall-mute:before {
+ content: "\e906";
+}
+.icon-activecall-pickup:before {
+ content: "\e907";
+}
+.icon-activecall-sms:before {
+ content: "\e908";
+}
+.icon-activecall-speaker:before {
+ content: "\e909";
+}
+.icon-activecall-switchlines:before {
+ content: "\e90a";
+}
+.icon-activecall-voicemail:before {
+ content: "\e90b";
+}
+.icon-add:before {
+ content: "\e90c";
+}
+.icon-addons:before {
+ content: "\e90d";
+}
+.icon-airplane:before {
+ content: "\e90e";
+}
+.icon-alarm-clock:before {
+ content: "\e90f";
+}
+.icon-alarmstop:before {
+ content: "\e910";
+}
+.icon-album:before {
+ content: "\e911";
+}
+.icon-all-day:before {
+ content: "\e912";
+}
+.icon-apps:before {
+ content: "\e913";
+}
+.icon-artist:before {
+ content: "\e914";
+}
+.icon-attachments:before {
+ content: "\e915";
+}
+.icon-audio:before {
+ content: "\e916";
+}
+.icon-auth:before {
+ content: "\e917";
+}
+.icon-auto-enhance-spark:before {
+ content: "\e918";
+}
+.icon-back:before {
+ content: "\e91a";
+}
+.icon-back-light:before {
+ content: "\e91b";
+}
+.icon-battery:before {
+ content: "\e91c";
+}
+.icon-battery-0:before {
+ content: "\e91d";
+}
+.icon-battery-10:before {
+ content: "\e91e";
+}
+.icon-battery-100:before {
+ content: "\e927";
+}
+.icon-battery-20:before {
+ content: "\e91f";
+}
+.icon-battery-30:before {
+ content: "\e920";
+}
+.icon-battery-40:before {
+ content: "\e921";
+}
+.icon-battery-50:before {
+ content: "\e922";
+}
+.icon-battery-60:before {
+ content: "\e923";
+}
+.icon-battery-70:before {
+ content: "\e924";
+}
+.icon-battery-80:before {
+ content: "\e925";
+}
+.icon-battery-90:before {
+ content: "\e926";
+}
+.icon-battery-charging:before {
+ content: "\e928";
+}
+.icon-battery-charging-0:before {
+ content: "\e929";
+}
+.icon-battery-charging-10:before {
+ content: "\e92a";
+}
+.icon-battery-charging-100:before {
+ content: "\e933";
+}
+.icon-battery-charging-20:before {
+ content: "\e92b";
+}
+.icon-battery-charging-30:before {
+ content: "\e92c";
+}
+.icon-battery-charging-40:before {
+ content: "\e92d";
+}
+.icon-battery-charging-50:before {
+ content: "\e92e";
+}
+.icon-battery-charging-60:before {
+ content: "\e92f";
+}
+.icon-battery-charging-70:before {
+ content: "\e930";
+}
+.icon-battery-charging-80:before {
+ content: "\e931";
+}
+.icon-battery-charging-90:before {
+ content: "\e932";
+}
+.icon-bell:before {
+ content: "\e934";
+}
+.icon-bluetooth:before {
+ content: "\e935";
+}
+.icon-bookmark:before {
+ content: "\e936";
+}
+.icon-bookmarked:before {
+ content: "\e937";
+}
+.icon-brightness:before {
+ content: "\e938";
+}
+.icon-browser-back:before {
+ content: "\e939";
+}
+.icon-browser-closecancel:before {
+ content: "\e93a";
+}
+.icon-browser-crashedtab:before {
+ content: "\e93b";
+}
+.icon-browser-forward:before {
+ content: "\e93c";
+}
+.icon-browser-home:before {
+ content: "\e93d";
+}
+.icon-browser-library:before {
+ content: "\e93e";
+}
+.icon-browser-moretabs:before {
+ content: "\e93f";
+}
+.icon-browser-nofavicon:before {
+ content: "\e940";
+}
+.icon-browser-pictureinpicture:before {
+ content: "\e941";
+}
+.icon-browser-readermode:before {
+ content: "\e942";
+}
+.icon-browser-reload:before {
+ content: "\e943";
+}
+.icon-browser-search:before {
+ content: "\e944";
+}
+.icon-browser-secure:before {
+ content: "\e945";
+}
+.icon-browser-secureunverified:before {
+ content: "\e946";
+}
+.icon-browser-sidetabs:before {
+ content: "\e947";
+}
+.icon-browser-tabpreviews:before {
+ content: "\e948";
+}
+.icon-browsing:before {
+ content: "\e949";
+}
+.icon-bug:before {
+ content: "\e94a";
+}
+.icon-calendar-alarm:before {
+ content: "\e94b";
+}
+.icon-calendar-allday:before {
+ content: "\e94c";
+}
+.icon-calendar-bullet:before {
+ content: "\e94d";
+}
+.icon-calendar-dot:before {
+ content: "\e94e";
+}
+.icon-calendar-eventalarm:before {
+ content: "\e94f";
+}
+.icon-calendar-today:before {
+ content: "\e950";
+}
+.icon-call:before {
+ content: "\e951";
+}
+.icon-call-incoming:before {
+ content: "\e952";
+}
+.icon-call-outgoing:before {
+ content: "\e95c";
+}
+.icon-call-ringing:before {
+ content: "\e95d";
+}
+.icon-calllog-checkboxoff:before {
+ content: "\e953";
+}
+.icon-calllog-checkboxon-box:before {
+ content: "\e954";
+}
+.icon-calllog-checkboxon-checkmark:before {
+ content: "\e955";
+}
+.icon-calllog-expand:before {
+ content: "\e956";
+}
+.icon-calllog-incomingcall:before {
+ content: "\e957";
+}
+.icon-calllog-incomingsms:before {
+ content: "\e958";
+}
+.icon-calllog-missedcall:before {
+ content: "\e959";
+}
+.icon-calllog-outgoingcall:before {
+ content: "\e95a";
+}
+.icon-calllog-outgoingsms:before {
+ content: "\e95b";
+}
+.icon-camera:before {
+ content: "\e95e";
+}
+.icon-camera-cameraorientation:before {
+ content: "\e95f";
+}
+.icon-camera-flashauto:before {
+ content: "\e960";
+}
+.icon-camera-flashoff:before {
+ content: "\e961";
+}
+.icon-camera-flashon:before {
+ content: "\e962";
+}
+.icon-camera-videorecorder:before {
+ content: "\e963";
+}
+.icon-change-wallpaper:before {
+ content: "\e964";
+}
+.icon-checked:before {
+ content: "\e965";
+}
+.icon-clear-all:before {
+ content: "\e966";
+}
+.icon-clearcancel-circle:before {
+ content: "\e967";
+}
+.icon-clearcancel-cross:before {
+ content: "\e968";
+}
+.icon-close:before {
+ content: "\e969";
+}
+.icon-closecancel:before {
+ content: "\e96a";
+}
+.icon-collapse-chevron:before {
+ content: "\e96b";
+}
+.icon-compose:before {
+ content: "\e96c";
+}
+.icon-contact-add:before {
+ content: "\e96d";
+}
+.icon-contact-addfavorite:before {
+ content: "\e96e";
+}
+.icon-contact-addimage:before {
+ content: "\e96f";
+}
+.icon-contact-checkmark:before {
+ content: "\e970";
+}
+.icon-contact-delete-circle:before {
+ content: "\e971";
+}
+.icon-contact-delete-minus:before {
+ content: "\e972";
+}
+.icon-contact-detailfacebook-f:before {
+ content: "\e973";
+}
+.icon-contact-detailfacebook-square:before {
+ content: "\e974";
+}
+.icon-contact-email:before {
+ content: "\e975";
+}
+.icon-contact-favorite:before {
+ content: "\e976";
+}
+.icon-contact-favorited:before {
+ content: "\e977";
+}
+.icon-contact-favoritedcontact:before {
+ content: "\e978";
+}
+.icon-contact-find:before {
+ content: "\e979";
+}
+.icon-contact-link:before {
+ content: "\e97a";
+}
+.icon-contact-location:before {
+ content: "\e97b";
+}
+.icon-contact-phone:before {
+ content: "\e97c";
+}
+.icon-contact-sms:before {
+ content: "\e97e";
+}
+.icon-contact-twitter:before {
+ content: "\e97f";
+}
+.icon-contact-undo-roundarrow:before {
+ content: "\e981";
+}
+.icon-contacts:before {
+ content: "\e97d";
+}
+.icon-copy:before {
+ content: "\e982";
+}
+.icon-costcontrol-topup:before {
+ content: "\e983";
+}
+.icon-costcontrol-topuppay:before {
+ content: "\e984";
+}
+.icon-costcontrol-topupwithcode:before {
+ content: "\e985";
+}
+.icon-costcontrol-updatebalance:before {
+ content: "\e986";
+}
+.icon-crop:before {
+ content: "\e987";
+}
+.icon-cut:before {
+ content: "\e988";
+}
+.icon-data:before {
+ content: "\e989";
+}
+.icon-database:before {
+ content: "\e98a";
+}
+.icon-delete:before {
+ content: "\e98b";
+}
+.icon-desktop:before {
+ content: "\e98c";
+}
+.icon-developer:before {
+ content: "\e98d";
+}
+.icon-dialer-contacts:before {
+ content: "\e98e";
+}
+.icon-dialer-delete:before {
+ content: "\e98f";
+}
+.icon-dialer-dialpad:before {
+ content: "\e990";
+}
+.icon-dialer-recentcalls:before {
+ content: "\e991";
+}
+.icon-dialpad:before {
+ content: "\e992";
+}
+.icon-discord:before {
+ content: "\e993";
+}
+.icon-dislike:before {
+ content: "\e994";
+}
+.icon-disliked:before {
+ content: "\e995";
+}
+.icon-dismisskeyboard:before {
+ content: "\e996";
+}
+.icon-display:before {
+ content: "\e997";
+}
+.icon-do-not-track:before {
+ content: "\e998";
+}
+.icon-download:before {
+ content: "\e999";
+}
+.icon-download-circle:before {
+ content: "\e99a";
+}
+.icon-edit:before {
+ content: "\e99b";
+}
+.icon-edit-image:before {
+ content: "\e99d";
+}
+.icon-editcontact:before {
+ content: "\e99c";
+}
+.icon-eject:before {
+ content: "\e99e";
+}
+.icon-email:before {
+ content: "\e99f";
+}
+.icon-email-addrecipient-circle:before {
+ content: "\e9a0";
+}
+.icon-email-addrecipient-plus:before {
+ content: "\e9a1";
+}
+.icon-email-attachment:before {
+ content: "\e9a2";
+}
+.icon-email-downloadattachment:before {
+ content: "\e9a3";
+}
+.icon-email-flag:before {
+ content: "\e9a4";
+}
+.icon-email-forward:before {
+ content: "\e9a5";
+}
+.icon-email-markread:before {
+ content: "\e9a6";
+}
+.icon-email-markunread:before {
+ content: "\e9a7";
+}
+.icon-email-move:before {
+ content: "\e9a8";
+}
+.icon-email-removeattachment-circle:before {
+ content: "\e9a9";
+}
+.icon-email-removeattachment-cross:before {
+ content: "\e9aa";
+}
+.icon-email-reply:before {
+ content: "\e9ab";
+}
+.icon-email-replyall:before {
+ content: "\e9ac";
+}
+.icon-email-send:before {
+ content: "\e9ad";
+}
+.icon-emailsmscalilog-editlist:before {
+ content: "\e9ae";
+}
+.icon-emojis:before {
+ content: "\e9af";
+}
+.icon-eraser:before {
+ content: "\e9b0";
+}
+.icon-expand:before {
+ content: "\e9b1";
+}
+.icon-expand-chevron:before {
+ content: "\e9b2";
+}
+.icon-export:before {
+ content: "\e9b3";
+}
+.icon-face-recognition:before {
+ content: "\e9b5";
+}
+.icon-face-recognition-fail:before {
+ content: "\e9b6";
+}
+.icon-facebook:before {
+ content: "\e9b4";
+}
+.icon-favorites:before {
+ content: "\e9b7";
+}
+.icon-feedback:before {
+ content: "\e9b8";
+}
+.icon-file:before {
+ content: "\e9b9";
+}
+.icon-find:before {
+ content: "\e9ba";
+}
+.icon-fingerprint:before {
+ content: "\e9bb";
+}
+.icon-firefox:before {
+ content: "\e9bc";
+}
+.icon-flag:before {
+ content: "\e9bd";
+}
+.icon-flashlight:before {
+ content: "\e9be";
+}
+.icon-fm-favouritedstation:before {
+ content: "\e9bf";
+}
+.icon-fm-sound:before {
+ content: "\e9c0";
+}
+.icon-folder:before {
+ content: "\e9c1";
+}
+.icon-forbidden:before {
+ content: "\e9c2";
+}
+.icon-forward:before {
+ content: "\e9c3";
+}
+.icon-forward-light:before {
+ content: "\e9c4";
+}
+.icon-ftu-importgmail:before {
+ content: "\e9c5";
+}
+.icon-ftu-importoutlook:before {
+ content: "\e9c6";
+}
+.icon-ftu-importsdcard:before {
+ content: "\e9c7";
+}
+.icon-ftu-importsim:before {
+ content: "\e9c8";
+}
+.icon-fullscreen:before {
+ content: "\e9c9";
+}
+.icon-fullscreen-exit:before {
+ content: "\e9ca";
+}
+.icon-gallery-autoenhancespark:before {
+ content: "\e9cb";
+}
+.icon-gallery-crop:before {
+ content: "\e9cd";
+}
+.icon-gallery-crop-photo:before {
+ content: "\e9d2";
+}
+.icon-gallery-crop1x1-mark:before {
+ content: "\e9ce";
+}
+.icon-gallery-crop2x3-mark:before {
+ content: "\e9cf";
+}
+.icon-gallery-crop3x2-mark:before {
+ content: "\e9d0";
+}
+.icon-gallery-cropfree-mark:before {
+ content: "\e9d1";
+}
+.icon-gallery-exposure:before {
+ content: "\e9d3";
+}
+.icon-gallery-filterscircleopacity100:before {
+ content: "\e9d6";
+}
+.icon-gallery-filterscircleopacity35:before {
+ content: "\e9d4";
+}
+.icon-gallery-filterscircleopacity50:before {
+ content: "\e9d5";
+}
+.icon-gallery-rotate:before {
+ content: "\e9d7";
+}
+.icon-game:before {
+ content: "\e9d8";
+}
+.icon-gerneral-unlock:before {
+ content: "\e9d9";
+}
+.icon-gesture:before {
+ content: "\e9da";
+}
+.icon-gmail:before {
+ content: "\e9db";
+}
+.icon-google:before {
+ content: "\e9dc";
+}
+.icon-grid:before {
+ content: "\e9dd";
+}
+.icon-heart:before {
+ content: "\e9de";
+}
+.icon-help:before {
+ content: "\e9df";
+}
+.icon-history:before {
+ content: "\e9e0";
+}
+.icon-home:before {
+ content: "\e9e1";
+}
+.icon-homescreen:before {
+ content: "\e9e2";
+}
+.icon-homescreendelete-circle:before {
+ content: "\e9e3";
+}
+.icon-homescreendelete-cross:before {
+ content: "\e9e4";
+}
+.icon-info:before {
+ content: "\e9e5";
+}
+.icon-instagram:before {
+ content: "\e9e6";
+}
+.icon-iris-scanner:before {
+ content: "\e9e7";
+}
+.icon-iris-scanner-fail:before {
+ content: "\e9e8";
+}
+.icon-iris-scanner-success:before {
+ content: "\e9e9";
+}
+.icon-keyboard:before {
+ content: "\e9ea";
+}
+.icon-keyboard-circle:before {
+ content: "\e9eb";
+}
+.icon-languages:before {
+ content: "\e9ec";
+}
+.icon-left:before {
+ content: "\e9ed";
+}
+.icon-left-light:before {
+ content: "\e9ee";
+}
+.icon-library:before {
+ content: "\e9ef";
+}
+.icon-like:before {
+ content: "\e9f0";
+}
+.icon-liked:before {
+ content: "\e9f1";
+}
+.icon-link:before {
+ content: "\e9f2";
+}
+.icon-linkedin:before {
+ content: "\e9f3";
+}
+.icon-location:before {
+ content: "\e9f4";
+}
+.icon-lock:before {
+ content: "\e9f5";
+}
+.icon-logout:before {
+ content: "\e9f6";
+}
+.icon-media-camera:before {
+ content: "\e9f7";
+}
+.icon-media-info:before {
+ content: "\e9f8";
+}
+.icon-media-pause:before {
+ content: "\e9f9";
+}
+.icon-media-play:before {
+ content: "\e9fa";
+}
+.icon-media-playcircle:before {
+ content: "\e9fb";
+}
+.icon-media-repeatinfinite:before {
+ content: "\e9fc";
+}
+.icon-media-repeatonce:before {
+ content: "\e9fd";
+}
+.icon-media-seekbackward:before {
+ content: "\e9fe";
+}
+.icon-media-seekforward:before {
+ content: "\e9ff";
+}
+.icon-media-shuffle:before {
+ content: "\ea00";
+}
+.icon-media-skipbackward:before {
+ content: "\ea01";
+}
+.icon-media-skipforward:before {
+ content: "\ea02";
+}
+.icon-media-songs:before {
+ content: "\ea03";
+}
+.icon-media-stop:before {
+ content: "\ea04";
+}
+.icon-media-storage:before {
+ content: "\ea05";
+}
+.icon-menu:before {
+ content: "\ea06";
+}
+.icon-messages:before {
+ content: "\ea07";
+}
+.icon-mic:before {
+ content: "\ea08";
+}
+.icon-miscellaneous-editimage:before {
+ content: "\ea09";
+}
+.icon-miscellaneous-select:before {
+ content: "\ea0a";
+}
+.icon-miscellaneous-undo:before {
+ content: "\ea0b";
+}
+.icon-moderator:before {
+ content: "\ea0c";
+}
+.icon-moon:before {
+ content: "\ea0d";
+}
+.icon-more:before {
+ content: "\ea0e";
+}
+.icon-music-album:before {
+ content: "\ea0f";
+}
+.icon-music-artist:before {
+ content: "\ea10";
+}
+.icon-music-gridview:before {
+ content: "\ea11";
+}
+.icon-music-playlist:before {
+ content: "\ea12";
+}
+.icon-newadd:before {
+ content: "\ea13";
+}
+.icon-nfc:before {
+ content: "\ea14";
+}
+.icon-notification-bluetooth:before {
+ content: "\ea15";
+}
+.icon-notification-bluetoothtransfer:before {
+ content: "\ea16";
+}
+.icon-notification-cameramic:before {
+ content: "\ea17";
+}
+.icon-notification-cameraon:before {
+ content: "\ea18";
+}
+.icon-notification-circle:before {
+ content: "\ea19";
+}
+.icon-notification-download:before {
+ content: "\ea1a";
+}
+.icon-notification-downloadfailed-exclamation:before {
+ content: "\ea1b";
+}
+.icon-notification-facebook:before {
+ content: "\ea1c";
+}
+.icon-notification-importingfrommemorycard:before {
+ content: "\ea1d";
+}
+.icon-notification-lowstorage:before {
+ content: "\ea1e";
+}
+.icon-notification-mic:before {
+ content: "\ea1f";
+}
+.icon-notifications:before {
+ content: "\ea20";
+}
+.icon-options:before {
+ content: "\ea21";
+}
+.icon-outlook:before {
+ content: "\ea22";
+}
+.icon-paintbrush:before {
+ content: "\ea23";
+}
+.icon-paintbucket:before {
+ content: "\ea24";
+}
+.icon-paste:before {
+ content: "\ea25";
+}
+.icon-pause:before {
+ content: "\ea26";
+}
+.icon-permissions:before {
+ content: "\ea27";
+}
+.icon-phone:before {
+ content: "\ea28";
+}
+.icon-picture-in-picture:before {
+ content: "\ea29";
+}
+.icon-pin:before {
+ content: "\ea2a";
+}
+.icon-play:before {
+ content: "\ea2b";
+}
+.icon-play-circle:before {
+ content: "\ea2c";
+}
+.icon-playlist:before {
+ content: "\ea2d";
+}
+.icon-power:before {
+ content: "\ea2e";
+}
+.icon-qr:before {
+ content: "\ea2f";
+}
+.icon-qr-scan:before {
+ content: "\ea30";
+}
+.icon-quote:before {
+ content: "\ea31";
+}
+.icon-reader-mode:before {
+ content: "\ea32";
+}
+.icon-recent-calls:before {
+ content: "\ea33";
+}
+.icon-redo:before {
+ content: "\ea34";
+}
+.icon-reload:before {
+ content: "\ea35";
+}
+.icon-repeat:before {
+ content: "\ea36";
+}
+.icon-repeat-once:before {
+ content: "\ea37";
+}
+.icon-right:before {
+ content: "\ea38";
+}
+.icon-right-light:before {
+ content: "\ea39";
+}
+.icon-save:before {
+ content: "\ea3a";
+}
+.icon-sdcard:before {
+ content: "\ea3b";
+}
+.icon-search:before {
+ content: "\ea3c";
+}
+.icon-select:before {
+ content: "\ea3d";
+}
+.icon-selectall:before {
+ content: "\ea3e";
+}
+.icon-send:before {
+ content: "\ea3f";
+}
+.icon-settings:before {
+ content: "\ea40";
+}
+.icon-settings-aboutphone:before {
+ content: "\ea41";
+}
+.icon-settings-accessibility:before {
+ content: "\ea42";
+}
+.icon-settings-airplane:before {
+ content: "\ea43";
+}
+.icon-settings-app-permissions:before {
+ content: "\ea44";
+}
+.icon-settings-apps:before {
+ content: "\ea45";
+}
+.icon-settings-appstorage:before {
+ content: "\ea46";
+}
+.icon-settings-battery:before {
+ content: "\ea47";
+}
+.icon-settings-bluetooth:before {
+ content: "\ea48";
+}
+.icon-settings-brightness:before {
+ content: "\ea49";
+}
+.icon-settings-brightness-lower:before {
+ content: "\ea4a";
+}
+.icon-settings-call:before {
+ content: "\ea4b";
+}
+.icon-settings-camera-permissions:before {
+ content: "\ea4c";
+}
+.icon-settings-changewallpapericon:before {
+ content: "\ea4e";
+}
+.icon-settings-contacts-permissions:before {
+ content: "\ea4f";
+}
+.icon-settings-developer:before {
+ content: "\ea50";
+}
+.icon-settings-deviceinfo:before {
+ content: "\ea51";
+}
+.icon-settings-devicestorage-permissions:before {
+ content: "\ea52";
+}
+.icon-settings-display:before {
+ content: "\ea53";
+}
+.icon-settings-donottrack:before {
+ content: "\ea54";
+}
+.icon-settings-download:before {
+ content: "\ea55";
+}
+.icon-settings-email:before {
+ content: "\ea56";
+}
+.icon-settings-facerecognition:before {
+ content: "\ea57";
+}
+.icon-settings-feedback:before {
+ content: "\ea58";
+}
+.icon-settings-findmydevice:before {
+ content: "\ea59";
+}
+.icon-settings-fingerprint:before {
+ content: "\ea5a";
+}
+.icon-settings-fmradio-permissions:before {
+ content: "\ea5b";
+}
+.icon-settings-gesture:before {
+ content: "\ea5c";
+}
+.icon-settings-gps:before {
+ content: "\ea5d";
+}
+.icon-settings-gps-permissions:before {
+ content: "\ea5e";
+}
+.icon-settings-help:before {
+ content: "\ea5f";
+}
+.icon-settings-helpx:before {
+ content: "\ea60";
+}
+.icon-settings-homescreen:before {
+ content: "\ea61";
+}
+.icon-settings-irisscanner:before {
+ content: "\ea62";
+}
+.icon-settings-languages:before {
+ content: "\ea63";
+}
+.icon-settings-mediastorage:before {
+ content: "\ea64";
+}
+.icon-settings-messages:before {
+ content: "\ea65";
+}
+.icon-settings-network:before {
+ content: "\ea66";
+}
+.icon-settings-nfc:before {
+ content: "\ea67";
+}
+.icon-settings-notifications:before {
+ content: "\ea68";
+}
+.icon-settings-persona:before {
+ content: "\ea69";
+}
+.icon-settings-phonelock:before {
+ content: "\ea6a";
+}
+.icon-settings-privacy:before {
+ content: "\ea6b";
+}
+.icon-settings-simcardlock:before {
+ content: "\ea6c";
+}
+.icon-settings-simtoolkit:before {
+ content: "\ea6d";
+}
+.icon-settings-sound-max:before {
+ content: "\ea6e";
+}
+.icon-settings-sound-min:before {
+ content: "\ea6f";
+}
+.icon-settings-tethering:before {
+ content: "\ea70";
+}
+.icon-settings-themes:before {
+ content: "\ea71";
+}
+.icon-settings-time:before {
+ content: "\ea72";
+}
+.icon-settings-usbstorage:before {
+ content: "\ea73";
+}
+.icon-settings-wallpaper:before {
+ content: "\ea74";
+}
+.icon-settings-wifi:before {
+ content: "\ea75";
+}
+.icon-settings-wifi-1:before {
+ content: "\ea76";
+}
+.icon-settings-wifi-2:before {
+ content: "\ea77";
+}
+.icon-settings-wifi-3:before {
+ content: "\ea78";
+}
+.icon-settings-wifi-4:before {
+ content: "\ea79";
+}
+.icon-settings-wifi-lock:before {
+ content: "\ea7a";
+}
+.icon-settings-wifi-lock-1:before {
+ content: "\ea7b";
+}
+.icon-settings-wifi-lock-2:before {
+ content: "\ea7c";
+}
+.icon-settings-wifi-lock-3:before {
+ content: "\ea7d";
+}
+.icon-settings-wifi-lock-4:before {
+ content: "\ea7e";
+}
+.icon-settings-wifi-permissions:before {
+ content: "\ea7f";
+}
+.icon-share:before {
+ content: "\ea80";
+}
+.icon-shopping-cart:before {
+ content: "\ea81";
+}
+.icon-shuffle:before {
+ content: "\ea82";
+}
+.icon-side-tabs:before {
+ content: "\ea83";
+}
+.icon-signal-1:before {
+ content: "\ea84";
+}
+.icon-signal-2:before {
+ content: "\ea85";
+}
+.icon-signal-3:before {
+ content: "\ea86";
+}
+.icon-signal-4:before {
+ content: "\ea87";
+}
+.icon-signal-5:before {
+ content: "\ea88";
+}
+.icon-sim:before {
+ content: "\ea89";
+}
+.icon-skip-back:before {
+ content: "\ea8a";
+}
+.icon-skip-forward:before {
+ content: "\ea8b";
+}
+.icon-sms:before {
+ content: "\ea8c";
+}
+.icon-snap-bottom:before {
+ content: "\ea8d";
+}
+.icon-snap-bottom-left:before {
+ content: "\ea8e";
+}
+.icon-snap-bottom-right:before {
+ content: "\ea8f";
+}
+.icon-snap-left:before {
+ content: "\ea90";
+}
+.icon-snap-right:before {
+ content: "\ea91";
+}
+.icon-snap-top:before {
+ content: "\ea92";
+}
+.icon-snap-top-left:before {
+ content: "\ea93";
+}
+.icon-snap-top-right:before {
+ content: "\ea94";
+}
+.icon-songs:before {
+ content: "\ea95";
+}
+.icon-sound-max:before {
+ content: "\ea96";
+}
+.icon-sound-min:before {
+ content: "\ea97";
+}
+.icon-speaker:before {
+ content: "\ea98";
+}
+.icon-splitscreen:before {
+ content: "\ea99";
+}
+.icon-spotify-svgrepo-com:before {
+ content: "\ea9a";
+}
+.icon-ssl:before {
+ content: "\ea9b";
+}
+.icon-ssl-broken:before {
+ content: "\ea9c";
+}
+.icon-stickers:before {
+ content: "\ea9d";
+}
+.icon-storage:before {
+ content: "\ea9e";
+}
+.icon-sync:before {
+ content: "\ea9f";
+}
+.icon-tab-previews:before {
+ content: "\eaa1";
+}
+.icon-tablet:before {
+ content: "\eaa0";
+}
+.icon-taskswitcherappclose-circle:before {
+ content: "\eaa2";
+}
+.icon-taskswitcherappclose-cross:before {
+ content: "\eaa3";
+}
+.icon-television:before {
+ content: "\eaa4";
+}
+.icon-tethering:before {
+ content: "\eaa5";
+}
+.icon-textselection-copy:before {
+ content: "\eaa6";
+}
+.icon-textselection-cut:before {
+ content: "\eaa7";
+}
+.icon-textselection-paste:before {
+ content: "\eaa8";
+}
+.icon-textselection-selectall:before {
+ content: "\eaa9";
+}
+.icon-themes:before {
+ content: "\eaaa";
+}
+.icon-threadnotsent-circle:before {
+ content: "\eaab";
+}
+.icon-threadnotsent-exclamation:before {
+ content: "\eaac";
+}
+.icon-tick:before {
+ content: "\eaad";
+}
+.icon-tick-circle:before {
+ content: "\eaae";
+}
+.icon-tiktok:before {
+ content: "\eaaf";
+}
+.icon-time:before {
+ content: "\eab0";
+}
+.icon-treadsent-check:before {
+ content: "\eab1";
+}
+.icon-treadsent-circle:before {
+ content: "\eab2";
+}
+.icon-tree:before {
+ content: "\eab3";
+}
+.icon-tv:before {
+ content: "\eab4";
+}
+.icon-twitch:before {
+ content: "\eab5";
+}
+.icon-twitter:before {
+ content: "\eab6";
+}
+.icon-undo:before {
+ content: "\eab7";
+}
+.icon-upload:before {
+ content: "\eab8";
+}
+.icon-usb:before {
+ content: "\eab9";
+}
+.icon-user:before {
+ content: "\eaba";
+}
+.icon-useraccoun-headers:before {
+ content: "\eabb";
+}
+.icon-utility-airplanemode:before {
+ content: "\eabc";
+}
+.icon-utility-arrow:before {
+ content: "\eabd";
+}
+.icon-utility-battery:before {
+ content: "\eabe";
+}
+.icon-utility-bluetooth:before {
+ content: "\eabf";
+}
+.icon-utility-brightness:before {
+ content: "\eac0";
+}
+.icon-utility-camera-lockedscreen:before {
+ content: "\eac1";
+}
+.icon-utility-data:before {
+ content: "\eac2";
+}
+.icon-utility-flashlight:before {
+ content: "\eac3";
+}
+.icon-utility-maxvolume:before {
+ content: "\eac4";
+}
+.icon-utility-mute-cease:before {
+ content: "\eac5";
+}
+.icon-utility-mute-speaker:before {
+ content: "\eac6";
+}
+.icon-utility-vibrate:before {
+ content: "\eac7";
+}
+.icon-utility-volume:before {
+ content: "\eac8";
+}
+.icon-utility-wifi:before {
+ content: "\eac9";
+}
+.icon-vibrate:before {
+ content: "\eaca";
+}
+.icon-video:before {
+ content: "\eacb";
+}
+.icon-vpn:before {
+ content: "\eacc";
+}
+.icon-wallpaper:before {
+ content: "\eacd";
+}
+.icon-web:before {
+ content: "\eace";
+}
+.icon-wifi:before {
+ content: "\eacf";
+}
+.icon-wifi-1:before {
+ content: "\ead0";
+}
+.icon-wifi-2:before {
+ content: "\ead1";
+}
+.icon-wifi-3:before {
+ content: "\ead2";
+}
+.icon-wifi-4:before {
+ content: "\ead3";
+}
+.icon-windows:before {
+ content: "\ead4";
+}
+.icon-wm-snapbottom:before {
+ content: "\ead5";
+}
+.icon-wm-snapbottomleft:before {
+ content: "\ead6";
+}
+.icon-wm-snapbottomright:before {
+ content: "\ead7";
+}
+.icon-wm-snapleft:before {
+ content: "\ead8";
+}
+.icon-wm-snapright:before {
+ content: "\ead9";
+}
+.icon-wm-snaptop:before {
+ content: "\eada";
+}
+.icon-wm-snaptopleft:before {
+ content: "\eadb";
+}
+.icon-wm-snaptopright:before {
+ content: "\eadc";
+}
+.icon-youtube:before {
+ content: "\eadd";
+}
diff --git a/things/lists.css b/things/lists.css
new file mode 100644
index 0000000..eb62410
--- /dev/null
+++ b/things/lists.css
@@ -0,0 +1,122 @@
+.lists header {
+ width: 100%;
+ max-width: 74.8rem;
+ padding: 0 2rem;
+ box-sizing: border-box;
+ height: 3rem;
+ line-height: 3rem;
+ color: #858585;
+ font-size: 1.6rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin: 1rem auto 0;
+}
+
+.lists ul {
+ margin: 0 auto 1.5rem;
+ padding: 0.5rem;
+ background-color: var(--background-plus);
+ border-radius: 1.5rem;
+ width: calc(100% - 3rem);
+ max-width: 71.8rem;
+ box-sizing: border-box;
+}
+
+.lists ul li {
+ position: relative;
+ margin: 0;
+ list-style: none;
+ min-height: 5rem;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ width: 100%;
+ padding: 0 1.5rem;
+ box-sizing: border-box;
+ border-radius: 1rem;
+ color: var(--text-color);
+}
+
+.lists ul li:hover {
+ background-color: var(--item-hover);
+}
+
+.lists ul li:active {
+ background-color: var(--item-active);
+}
+
+.lists ul li.selected {
+ background-color: var(--accent-color);
+ color: var(--accent-color-plus);
+}
+
+.lists ul li[data-icon] {
+ padding-inline-start: 4.5rem;
+}
+
+.lists ul li[data-icon]::before {
+ position: absolute;
+ top: 50%;
+ margin-top: -1.2rem;
+ left: 1.2rem;
+ color: var(--text-color);
+ width: 2.4rem;
+ height: 2.4rem;
+ line-height: 2.4rem;
+ font-size: 2.4rem;
+}
+
+.lists ul li.selected[data-icon]::before {
+ color: var(--accent-color-plus);
+}
+
+.lists ul li.page::after {
+ content: 'forward';
+ font-family: "openorchid-icons";
+ font-size: 2rem;
+ color: #858585;
+ text-align: end;
+ line-height: 5rem;
+}
+
+.lists ul li.page.selected::after {
+ color: var(--accent-color-plus);
+ opacity: 0.5;
+}
+
+.lists ul li::after {
+ content: '';
+ position: absolute;
+ left: 1.5rem;
+ top: 0;
+ width: calc(100% - 3rem);
+ height: 100%;
+ pointer-events: none;
+ border-bottom: solid 0.1rem var(--item-hover);
+ box-sizing: border-box;
+}
+
+.lists ul li:hover::after,
+.lists ul li:active::after,
+.lists ul li:last-child::after {
+ border-bottom: none;
+}
+
+.lists ul li p {
+ margin: 0;
+ height: 2.2rem;
+ line-height: 2.2rem;
+ font-size: 1.6rem;
+ color: var(--text-color);
+}
+
+.lists ul li.selected p {
+ color: var(--accent-color-plus);
+}
+
+.lists ul li p:not(:first-child) {
+ height: 1.9rem;
+ line-height: 1.9rem;
+ font-size: 1.4rem;
+ opacity: 0.5;
+}
diff --git a/things/main.css b/things/main.css
new file mode 100644
index 0000000..e2c8636
--- /dev/null
+++ b/things/main.css
@@ -0,0 +1,15 @@
+html, body {
+ margin: 0;
+ padding: 0;
+ font-size: 10px;
+}
+
+.app {
+ --statusbar-height: 4rem;
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--background);
+}
diff --git a/things/panels.css b/things/panels.css
new file mode 100644
index 0000000..b05a798
--- /dev/null
+++ b/things/panels.css
@@ -0,0 +1,100 @@
+.panel {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--background);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ z-index: 50;
+}
+
+.panel > .content {
+ width: 100%;
+ height: 100%;
+ flex-grow: 1;
+ overflow-y: auto;
+ margin-top: calc((-5rem - var(--statusbar-height)) * var(--progress, 0));
+ scrollbar-width: none;
+}
+
+.panel > .content aside {
+ margin: 0 auto 1.5rem;
+ padding: 0;
+ background-color: var(--background-minus);
+ border-radius: 1.5rem;
+ width: calc(100% - 3rem);
+ max-width: 71.8rem;
+ box-sizing: border-box;
+}
+
+.panel > .content aside header {
+ width: 100%;
+ padding: 0 2rem;
+ box-sizing: border-box;
+ height: 3rem;
+ line-height: 3rem;
+ color: #858585;
+ font-size: 1.6rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ margin: 1rem 0 0;
+}
+
+.panel > .content aside ul {
+ margin: 0;
+ padding: 0 0.5rem 0.5rem;
+ width: 100%;
+ background-color: transparent;
+}
+
+.panel > .content aside ul li {
+ min-height: 3.2rem;
+ background-color: transparent;
+}
+
+.panel > .content aside ul li > a {
+ color: var(--accent-color);
+ width: max-content;
+ line-height: 2.2rem;
+ font-size: 1.6rem;
+ text-decoration: none;
+ transition: box-shadow 0.2s ease;
+}
+
+.panel > .content aside ul li > a:hover {
+ box-shadow: 0 0.2rem 0 var(--accent-color);
+}
+
+.panel > .content aside ul li > a:active {
+ opacity: 0.5;
+}
+
+@media screen and (min-width: 983px) {
+ .panel > .headerbar .safezone {
+ margin-inline-start: 0;
+ }
+
+ .panel > .content header,
+ .panel > .content ul {
+ margin-inline-start: 1.5rem;
+ }
+
+ .panel > .content aside {
+ position: absolute;
+ right: 0;
+ top: calc(5rem + var(--statusbar-height) + (4rem * (1 - var(--progress, 0))));
+ width: 22rem;
+ margin: calc(1.5rem * var(--progress, 0)) 1.5rem 1.5rem;
+ }
+}
+
+@media screen and (min-width: 1536px) {
+ .panel > .headerbar .safezone,
+ .panel > .content header,
+ .panel > .content ul {
+ margin-inline-start: auto;
+ }
+}
diff --git a/things/switches.css b/things/switches.css
new file mode 100644
index 0000000..be56c72
--- /dev/null
+++ b/things/switches.css
@@ -0,0 +1,83 @@
+.pack-switch {
+ width: 100%;
+ display: inline-flex;
+}
+
+.pack-switch > label {
+ width: 100%;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ flex-grow: 1;
+}
+
+.pack-switch > span {
+ flex-shrink: 0;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.pack-switch > span input[type="checkbox"] {
+ background-color: var(--switch-normal);
+ width: 5rem;
+ height: 2.5rem;
+ border-radius: 2.5rem;
+ border: none;
+ position: relative;
+ outline: none;
+ appearance: none;
+ transition: all 0.1s ease;
+}
+
+.pack-switch > span input[type="checkbox"]:hover {
+ background-color: var(--switch-hover);
+}
+
+.pack-switch > span input[type="checkbox"]:hover {
+ background-color: var(--switch-active);
+}
+
+.pack-switch > span input[type="checkbox"]:checked {
+ background-color: var(--accent-color);
+}
+
+.pack-switch > span input[type="checkbox"]::before {
+ content: '';
+ position: absolute;
+ left: 0.5rem;
+ top: 0.5rem;
+ width: 1.5rem;
+ height: 1.5rem;
+ background-color: var(--text-color);
+ border-radius: 1.5rem;
+ transition: all 0.3s cubic-bezier(0.2, 0, 0, 1);
+ z-index: 1;
+ pointer-events: none;
+}
+
+.pack-switch > span input[type="checkbox"]:hover::before {
+ transform: scale(1.2);
+}
+
+.pack-switch > span input[type="checkbox"]:active::before {
+ transform: scale(0.8);
+ width: 4rem;
+}
+
+.pack-switch > span input[type="checkbox"]:checked::before {
+ left: 3rem;
+ transform: scale(1);
+ background-color: var(--accent-color-plus);
+}
+
+.pack-switch > span input[type="checkbox"]:checked:hover::before {
+ transform: scale(1.2);
+}
+
+.pack-switch > span input[type="checkbox"]:checked:active::before {
+ left: 0.5rem;
+ transform: scale(0.8);
+ width: 4rem;
+}
\ No newline at end of file
diff --git a/things/tablists.css b/things/tablists.css
new file mode 100644
index 0000000..e69de29
diff --git a/things/theme.css b/things/theme.css
new file mode 100644
index 0000000..3690514
--- /dev/null
+++ b/things/theme.css
@@ -0,0 +1,61 @@
+:root {
+ --accent-color: #0061e0;
+ --accent-color-plus: rgba(255, 255, 255, 0.75);
+ --accent-color-hover: rgba(255, 255, 255, 0.05);
+ --accent-color-active: rgba(255, 255, 255, 0.1);
+
+ --background: #f0f6ff;
+ --background-plus: #fff;
+ --background-minus: #e0edff;
+
+ --acrylic-background: rgba(224, 237, 255, 0.5);
+ --acrylic-background-plus: rgba(255, 255, 255, 0.75);
+
+ --text-color: #333;
+
+ --item-plus: rgba(0, 0, 0, 0.05);
+ --item-hover: rgba(0, 0, 0, 0.05);
+ --item-hover-plus: rgba(0, 0, 0, 0.1);
+ --item-active: rgba(0, 0, 0, 0.1);
+ --item-active-plus: rgba(0, 0, 0, 0.15);
+
+ --headerbar-r: 224;
+ --headerbar-g: 237;
+ --headerbar-b: 255;
+
+ --switch-normal: #d0e3ff;
+ --switch-hover: #c0d9ff;
+ --switch-active: #b0d0ff;
+}
+
+@media screen and (prefers-color-scheme: dark) {
+ :root {
+ --accent-color: #80c2ff;
+ --accent-color-plus: rgba(0, 0, 0, 0.75);
+ --accent-color-hover: rgba(0, 0, 0, 0.05);
+ --accent-color-active: rgba(0, 0, 0, 0.1);
+
+ --background: #000;
+ --background-plus: #212326;
+ --background-minus: #101215;
+
+ --acrylic-background: rgba(16, 18, 21, 0.5);
+ --acrylic-background-plus: rgba(33, 35, 38, 0.75);
+
+ --text-color: #e7e7e7;
+
+ --item-plus: rgba(255, 255, 255, 0.05);
+ --item-hover: rgba(255, 255, 255, 0.05);
+ --item-hover-plus: rgba(255, 255, 255, 0.1);
+ --item-active: rgba(255, 255, 255, 0.1);
+ --item-active-plus: rgba(255, 255, 255, 0.15);
+
+ --headerbar-r: 16;
+ --headerbar-g: 18;
+ --headerbar-b: 21;
+
+ --switch-normal: #101215;
+ --switch-hover: #303235;
+ --switch-active: #404245;
+ }
+}
diff --git a/things/webview.css b/things/webview.css
new file mode 100644
index 0000000..b81fc92
--- /dev/null
+++ b/things/webview.css
@@ -0,0 +1,17 @@
+*, ::placeholder {
+ font-family: system-ui;
+}
+
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: #858585;
+ background-clip: content-box;
+ border: 2px solid transparent;
+ border-radius: 8px;
+ width: 8px;
+ height: 8px;
+}