diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 000000000..b2e44dc39
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,8 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(node:*)",
+ "Bash(python3:*)"
+ ]
+ }
+}
diff --git a/.env b/.env
new file mode 100644
index 000000000..144c083b4
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+VERSION=9.0.0
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2c2f5ff74..d23da1df0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,4 @@ demo/shield-agent/in
demo/shield-core/in
demo/shared
demo/cached
+/.vscode
diff --git a/.vscode/dryrun.log b/.vscode/dryrun.log
index 46b63aab3..ebf85edcf 100644
--- a/.vscode/dryrun.log
+++ b/.vscode/dryrun.log
@@ -1,3 +1,4 @@
+make.exe --dry-run --always-make --keep-going --print-directory
'make.exe' is not recognized as an internal or external command,
operable program or batch file.
diff --git a/Dockerfile b/Dockerfile
index a56fb537f..7f2fb9e1b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.21-bookworm as build
+FROM golang:1.23-bookworm as build
RUN apt-get update \
&& apt-get install -y bzip2 gzip unzip curl openssh-client
@@ -9,6 +9,8 @@ RUN curl -sLo /bin/jq https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq
ARG VERSION
COPY / /go/src/github.com/shieldproject/shield/
RUN cd /go/src/github.com/shieldproject/shield \
+ && go mod tidy \
+ && go mod vendor \
&& make build BUILD_TYPE="build -ldflags='-X main.Version=$VERSION'"
RUN mkdir -p /dist/bin /dist/plugins \
&& mv /go/src/github.com/shieldproject/shield/shieldd \
diff --git a/Makefile b/Makefile
index 782ef4f03..b23c1bb89 100644
--- a/Makefile
+++ b/Makefile
@@ -50,18 +50,33 @@ help.all: cmd/shield/main.go
grep case $< | grep '{''{{' | cut -d\" -f 2 | sort | xargs -n1 -I@ ./shield @ -h > $@
# Building Plugins
+JOBS ?= $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1)
+
plugin: plugins
plugins:
- go $(BUILD_TYPE) -mod vendor ./plugin/dummy
+ @echo "Building dummy plugin..."
+ @go $(BUILD_TYPE) -mod vendor ./plugin/dummy || go $(BUILD_TYPE) ./plugin/dummy
@for plugin in $$(cat plugins); do \
- echo building plugin $$plugin...; \
- go $(BUILD_TYPE) -mod vendor ./plugin/$$plugin; \
+ echo "building plugin $$plugin..."; \
+ if ! go $(BUILD_TYPE) -mod vendor ./plugin/$$plugin; then \
+ GOFLAGS=-mod=mod go $(BUILD_TYPE) ./plugin/$$plugin; \
+ fi; \
done
demo: clean shield plugins
- ./demo/build
- (cd demo && docker-compose up)
+ @if [ -x ./demo/build ]; then \
+ ./demo/build; \
+ else \
+ echo "(warning) ./demo/build not found; skipping demo build"; \
+ fi
+ (cd docker/demo && docker compose up)
+
+# Local build stack (core/agent/demo/webdav from local source build)
+demo-local:
+ docker compose -f docker-compose.local.yml up --build
+
+dev-local: demo-local
docs: docs/dev/API.md
./bin/mkdocs --version latest --docroot /docs --output tmp/docs --style basic
@@ -85,7 +100,13 @@ fixmes: fixme
fixme:
@grep -rn FIXME * | grep -v vendor/ | grep -v README.md | grep --color FIXME || echo "No FIXMES! YAY!"
-dev:
+# Quick local development mode (UI + API) using docker-compose
+# Usage: make dev
+# then open http://localhost:9009
+dev: demo
+
+# Keep legacy testdev flow for deeper local test sandbox
+dev-test:
./bin/testdev
# Deferred: Naming plugins individually, e.g. make plugin dummy
diff --git a/docker-compose.local.yml b/docker-compose.local.yml
new file mode 100644
index 000000000..b36b97e3c
--- /dev/null
+++ b/docker-compose.local.yml
@@ -0,0 +1,101 @@
+version: '3'
+services:
+ vault:
+ image: hashicorp/vault:1.14
+ ports: ['8201:8200']
+ networks: [internal]
+ environment:
+ VAULT_API_ADDR: http://127.0.0.1:8200
+ VAULT_LOCAL_CONFIG: >-
+ {
+ "disable_mlock": 1,
+ "backend": {
+ "file": {
+ "path": "/vault/file"
+ }
+ },
+ "listener": {
+ "tcp": {
+ "address": "0.0.0.0:8201",
+ "tls_disable": 1
+ }
+ },
+ "default_lease_ttl": "168h",
+ "max_lease_ttl": "720h"
+ }
+ cap_add:
+ - IPC_LOCK
+ volumes:
+ - 'vault-data:/vault/file'
+
+ core:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ VERSION: local
+ image: shieldproject/shield:local-core
+ ports: ['9009:80']
+ networks: [internal]
+ command: ['/shield/init/core']
+ environment:
+ SHIELD_VAULT_ADDRESS: http://vault:8201
+ SHIELD_API_BIND: core:80
+ volumes:
+ - 'shield-data:/var/shield'
+ - 'shield-etc:/etc/shield'
+
+ webdav:
+ build:
+ context: docker/webdav
+ dockerfile: Dockerfile
+ ports: ['9007:80']
+ networks: [internal]
+ environment:
+ USERNAME: webdav
+ PASSWORD: password
+ volumes:
+ - 'webdav-data:/var/webdav'
+
+ agent:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ VERSION: local
+ image: shieldproject/shield:local-agent
+ depends_on:
+ - core
+ - webdav
+ ports: ['5444:5444']
+ networks: [internal]
+ command: ['/shield/init/agent']
+ environment:
+ SHIELD_API: 'http://core:80'
+ SHIELD_AGENT_NAME: 'demo-shield-agent'
+ volumes:
+ - 'shield-data:/var/shield'
+ - 'shield-etc:/etc/shield'
+ - 'demo-data:/www'
+
+ demo:
+ build:
+ context: docker/demo
+ dockerfile: Dockerfile
+ depends_on:
+ - core
+ - webdav
+ ports: ['9008:80']
+ networks: [internal]
+ volumes:
+ - 'demo-data:/www'
+
+networks:
+ internal:
+
+volumes:
+ vault-data:
+ shield-data:
+ shield-etc:
+ webdav-data:
+ demo-data:
diff --git a/plugin/postgres/plugin.go b/plugin/postgres/plugin.go
index 866fa08ce..577d98cbc 100644
--- a/plugin/postgres/plugin.go
+++ b/plugin/postgres/plugin.go
@@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"regexp"
+ "strings"
fmt "github.com/jhunt/go-ansi"
@@ -111,6 +112,14 @@ func main() {
Help: "The absolute path to the bin/ directory that contains the `psql` command.",
Default: "/var/vcap/packages/postgres-9.4/bin",
},
+ plugin.Field{
+ Mode: "target",
+ Name: "pg_skip_permission_check",
+ Type: "bool",
+ Title: "Skip permission validation",
+ Help: "Skip upfront permission checking. WARNING: Use only if you understand the risks. Restore may fail with confusing errors if privileges are insufficient.",
+ Default: "false",
+ },
},
}
@@ -120,15 +129,16 @@ func main() {
type PostgresPlugin plugin.PluginInfo
type PostgresConnectionInfo struct {
- Host string
- Port string
- User string
- Password string
- Bin string
- ReplicaHost string
- ReplicaPort string
- Database string
- Options string
+ Host string
+ Port string
+ User string
+ Password string
+ Bin string
+ ReplicaHost string
+ ReplicaPort string
+ Database string
+ Options string
+ SkipPermissionCheck bool
}
func (p PostgresPlugin) Meta() plugin.PluginInfo {
@@ -259,6 +269,15 @@ func (p PostgresPlugin) Restore(endpoint plugin.ShieldEndpoint) error {
setupEnvironmentVariables(pg)
+ // First, check if we have permission issues before starting the restore
+ if !pg.SkipPermissionCheck {
+ if err := checkRestorePermissions(pg); err != nil {
+ return err
+ }
+ } else {
+ plugin.DEBUG("Skipping permission check as requested")
+ }
+
cmd := exec.Command(fmt.Sprintf("%s/psql", pg.Bin), "-d", "postgres")
plugin.DEBUG("Exec: %s/psql -d postgres", pg.Bin)
plugin.DEBUG("Redirecting stdout and stderr to stderr")
@@ -316,6 +335,44 @@ func (p PostgresPlugin) Restore(endpoint plugin.ShieldEndpoint) error {
return <-scanErr
}
+// checkRestorePermissions performs upfront permission checks before starting restore
+func checkRestorePermissions(pg *PostgresConnectionInfo) error {
+ plugin.DEBUG("Checking restore permissions...")
+
+ // Create a temporary connection to check permissions
+ // Check if user is superuser or has specific database privileges
+ cmd := exec.Command(fmt.Sprintf("%s/psql", pg.Bin), "-d", "postgres", "-t", "-A", "-c",
+ "SELECT CASE WHEN "+
+ "(SELECT COALESCE(usesuper, false) FROM pg_user WHERE usename = current_user) OR "+
+ "pg_has_role(current_user, 'rds_superuser', 'MEMBER') OR "+
+ "(pg_has_role(current_user, 'pg_database_owner', 'MEMBER') AND has_database_privilege(current_user, 'postgres', 'CREATE')) "+
+ "THEN 'SUFFICIENT' ELSE 'INSUFFICIENT' END;")
+
+ cmd.Env = os.Environ()
+ cmd.Env = append(cmd.Env,
+ fmt.Sprintf("PGUSER=%s", pg.User),
+ fmt.Sprintf("PGPASSWORD=%s", pg.Password),
+ fmt.Sprintf("PGHOST=%s", pg.Host),
+ fmt.Sprintf("PGPORT=%s", pg.Port),
+ )
+
+ output, err := cmd.Output()
+ if err != nil {
+ plugin.DEBUG("Failed to check permissions: %s", err)
+ return fmt.Errorf("postgres: failed to verify user privileges: %s", err)
+ }
+
+ result := strings.TrimSpace(string(output))
+ plugin.DEBUG("Permission check result: '%s'", result)
+
+ if result != "SUFFICIENT" {
+ return fmt.Errorf("postgres: insufficient privileges for restore operation. User '%s' needs superuser privileges or database creation rights to safely restore databases", pg.User)
+ }
+
+ plugin.DEBUG("User has sufficient privileges for restore")
+ return nil
+}
+
func (p PostgresPlugin) Store(endpoint plugin.ShieldEndpoint) (string, int64, error) {
return "", 0, plugin.UNIMPLEMENTED
}
@@ -392,15 +449,22 @@ func pgConnectionInfo(endpoint plugin.ShieldEndpoint) (*PostgresConnectionInfo,
}
plugin.DEBUG("PGBINDIR: '%s'", bin)
+ skipCheck, err := endpoint.BooleanValueDefault("pg_skip_permission_check", false)
+ if err != nil {
+ return nil, err
+ }
+ plugin.DEBUG("PG_SKIP_PERMISSION_CHECK: %t", skipCheck)
+
return &PostgresConnectionInfo{
- Host: host,
- Port: port,
- User: user,
- Password: password,
- ReplicaHost: replicahost,
- ReplicaPort: replicaport,
- Bin: bin,
- Database: database,
- Options: options,
+ Host: host,
+ Port: port,
+ User: user,
+ Password: password,
+ ReplicaHost: replicahost,
+ ReplicaPort: replicaport,
+ Bin: bin,
+ Database: database,
+ Options: options,
+ SkipPermissionCheck: skipCheck,
}, nil
}
diff --git a/web/htdocs/bg.jpg b/web/htdocs/bg.jpg
new file mode 100644
index 000000000..7832d3d6d
Binary files /dev/null and b/web/htdocs/bg.jpg differ
diff --git a/web/htdocs/index.html b/web/htdocs/index.html
index 1648c99e9..ae08e7b79 100755
--- a/web/htdocs/index.html
+++ b/web/htdocs/index.html
@@ -5,12 +5,27 @@
+
This SHIELD Core is LOCKED
SHIELD needs to be unlocked before backup jobs (scheduled or ad hoc),
@@ -88,31 +87,50 @@
This SHIELD Core is LOCKED
The side-bar which contains options for restore and backup
]]
@@ -552,9 +570,20 @@
SOMETHING BROKE
current users name / tenant and "personal settings" menu.
]]
-
+
+ [[ if (AEGIS.authenticated() && AEGIS.current) { ]]
+
+ [[ } ]]
+
[[ if (AEGIS.authenticated()) { ]]
[[= h(AEGIS.user.name) ]][[ if (AEGIS.current) { ]] ([[= h(AEGIS.current.name) ]] :: [[= AEGIS.role(AEGIS.current.uuid) ]])[[ } ]]
diff --git a/web/htdocs/js/data.js b/web/htdocs/js/data.js
index 5659b2d9e..0aef23a61 100644
--- a/web/htdocs/js/data.js
+++ b/web/htdocs/js/data.js
@@ -403,14 +403,35 @@
subscribe: function (opts) {
opts = $.extend({
- bearings: '/v2/bearings',
- websocket: document.location.protocol.replace(/http/, 'ws')+'//'+document.location.host+'/v2/events'
- }, opts || {});
+ bearings: '/v2/bearings',
+ websocket: document.location.protocol.replace(/http/, 'ws') + '//' + document.location.host + '/v2/events'
+ }, opts);
var df = $.Deferred();
- var self = this; /* save off 'this' for the continuation call */
+ var self = this;
+
+ // Check authentication before establishing WebSocket
+ api({
+ type: 'GET',
+ url: opts.bearings,
+ success: function (bearings) {
+ if (bearings && bearings.user) {
+ self._establishWebSocket(opts, df, bearings);
+ } else {
+ df.reject();
+ }
+ },
+ error: function () {
+ df.reject();
+ }
+ });
+
+ return df.promise();
+ },
- console.log('connecting to websocket at %s', opts.websocket);
+ _establishWebSocket: function (opts, df, bearings, isReconnect) {
+ var self = this; /* save off 'this' for the continuation call */
+
this.ws = new WebSocket(opts.websocket);
this.ws.onerror = function (event) {
self.ws = undefined;
@@ -423,7 +444,7 @@
console.log('websocket closed, waiting 3000 ms before reopening to avoid infinite loop');
setTimeout(function() {
- self.subscribe();
+ self._reconnect();
}, (3 * 1000));
};
@@ -480,12 +501,13 @@
this.ws.onopen = function () {
console.log('connected to event stream.');
- self.clear()
- console.log('getting our bearings (via %s)...', opts.bearings);
- api({
- type: 'GET',
- url: opts.bearings,
- success: function (bearings) {
+
+ if (bearings) {
+ if (!isReconnect) {
+ // Only clear and reload all data on initial connection
+ self.clear();
+
+ // Process bearings data that was already fetched during authentication
self.shield = bearings.shield;
self.vault = bearings.vault;
self.user = bearings.user;
@@ -530,35 +552,64 @@
self.insert('tenant', tenant.tenant);
}
- console.log(bearings);
+ } else {
+ // On reconnection, just update core auth data and grants
+ self.shield = bearings.shield;
+ self.vault = bearings.vault;
+ self.user = bearings.user;
+
+ // Re-establish grants from fresh bearings data
+ for (var uuid in bearings.tenants) {
+ var tenant = bearings.tenants[uuid];
+ self.grant(uuid, tenant.role);
+ }
+ }
+ console.log(bearings);
- /* process system grants... */
- self.grant(self.user.sysrole);
+ /* process system grants... */
+ self.grant(self.user.sysrole);
- /* set default tenant */
- if (!self.current && self.data.tenant) {
- self.current = self.data.tenant[self.user.default_tenant];
- }
- if (!self.current) {
- var l = [];
- for (var k in self.data.tenant) {
- l.push(self.data.tenant[k]);
- }
- l.sort(function (a, b) {
- return a.name > b.name ? 1 : a.name == b.name ? 0 : -1;
- });
- if (l.length > 0) { self.current = l[0]; }
+ /* set default tenant */
+ if (!self.current && self.data.tenant) {
+ self.current = self.data.tenant[self.user.default_tenant];
+ }
+ if (!self.current) {
+ var l = [];
+ for (var k in self.data.tenant) {
+ l.push(self.data.tenant[k]);
}
-
- df.resolve();
- },
- error: function () {
- df.reject();
+ l.sort(function (a, b) {
+ return a.name > b.name ? 1 : a.name == b.name ? 0 : -1;
+ });
+ if (l.length > 0) { self.current = l[0]; }
}
- });
+ }
+
+ df.resolve();
};
+ },
- return df.promise();
+ _reconnect: function () {
+ var self = this;
+ console.log('attempting to reconnect websocket...');
+
+ // Validate authentication before reconnecting
+ api({
+ type: 'GET',
+ url: '/v2/bearings',
+ success: function (bearings) {
+ console.log('authentication still valid, reconnecting websocket...');
+ var opts = {
+ websocket: document.location.protocol.replace(/http/, 'ws')+'//'+document.location.host+'/v2/events'
+ };
+ var df = $.Deferred(); // Create dummy deferred since we don't need to track this
+ self._establishWebSocket(opts, df, bearings, true); // true = isReconnect
+ },
+ error: function () {
+ console.log('authentication expired during reconnection, redirecting to login...');
+ document.location.href = '/#!/login';
+ }
+ });
},
plugins: function (type) {
diff --git a/web/htdocs/js/events.js b/web/htdocs/js/events.js
index 1404ecb56..999417dca 100644
--- a/web/htdocs/js/events.js
+++ b/web/htdocs/js/events.js
@@ -699,6 +699,25 @@
});
}) /* }}} */
+ /* Theme toggle (dark / light) */
+ .on('click', '#theme-toggle', function () { /* {{{ */
+ var isLight = document.documentElement.getAttribute('data-theme') === 'light';
+ var next = isLight ? 'dark' : 'light';
+ if (next === 'dark') {
+ document.documentElement.removeAttribute('data-theme');
+ } else {
+ document.documentElement.setAttribute('data-theme', 'light');
+ }
+ document.cookie = 'shield-theme=' + next + '; path=/; max-age=' + (365 * 24 * 3600);
+ }) /* }}} */
+
+ /* Sidebar collapse toggle */
+ .on('click', '#sidebar-toggle', function () { /* {{{ */
+ var collapsed = $('.story-sidebar').toggleClass('collapsed').hasClass('collapsed');
+ $(document.body).toggleClass('sidebar-collapsed', collapsed);
+ localStorage.setItem('sidebar-collapsed', collapsed ? '1' : '0');
+ }) /* }}} */
+
/* Wizards (Shared) */
.on('wizard:step', '.wizard2', function (event, moving) { /* {{{ */
var $progress = $(event.target).find('.progress li');
diff --git a/web/htdocs/js/shield.js b/web/htdocs/js/shield.js
index ff85db98d..28c107004 100644
--- a/web/htdocs/js/shield.js
+++ b/web/htdocs/js/shield.js
@@ -1386,13 +1386,21 @@ $(function () {
$('#viewport').template('layout');
if (AEGIS.vault != "uninitialized") {
$('#side-bar').template('side-bar');
+ if (localStorage.getItem('sidebar-collapsed') === '1') {
+ $('.story-sidebar').addClass('collapsed');
+ $(document.body).addClass('sidebar-collapsed');
+ }
}
$('#hud').template('hud');
if (AEGIS.vault == "locked") {
$('#lock-state').fadeIn();
}
if (AEGIS.vault != "uninitialized") {
- $('#side-bar').template('side-bar')
+ $('#side-bar').template('side-bar');
+ if (localStorage.getItem('sidebar-collapsed') === '1') {
+ $('.story-sidebar').addClass('collapsed');
+ $(document.body).addClass('sidebar-collapsed');
+ }
}
}
$(document.body)
diff --git a/web/htdocs/shield.css b/web/htdocs/shield.css
index 8d58c2239..968b02f4f 100644
--- a/web/htdocs/shield.css
+++ b/web/htdocs/shield.css
@@ -1,3 +1,75 @@
+/* ================================================
+ SHIELD - Modern UI Theme
+ Dark mode by default with light mode support
+ ================================================ */
+
+/* CSS Variables for Theming */
+:root {
+ /* Dark Theme (Default) */
+ --bg-primary: #0d1117;
+ --bg-secondary: #161b22;
+ --bg-tertiary: #21262d;
+ --bg-elevated: #2d333b;
+ --bg-card: #1c2128;
+
+ --text-primary: #e6edf3;
+ --text-secondary: #8b949e;
+ --text-tertiary: #6e7681;
+
+ --accent-primary: #3b82f6;
+ --accent-hover: #2563eb;
+ --accent-light: #60a5fa;
+ --accent-dark: #1e40af;
+
+ --success: #10b981;
+ --warning: #f59e0b;
+ --error: #ef4444;
+ --info: #06b6d4;
+
+ --border-default: #30363d;
+ --border-muted: #21262d;
+
+ --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.6), 0 4px 6px -2px rgba(0, 0, 0, 0.4);
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.7), 0 10px 10px -5px rgba(0, 0, 0, 0.5);
+
+ --radius-sm: 6px;
+ --radius-md: 8px;
+ --radius-lg: 12px;
+ --radius-xl: 16px;
+}
+
+/* Light Theme */
+[data-theme="light"] {
+ --bg-primary: #ffffff;
+ --bg-secondary: #f6f8fa;
+ --bg-tertiary: #f0f3f6;
+ --bg-elevated: #ffffff;
+ --bg-card: #ffffff;
+
+ --text-primary: #1f2328;
+ --text-secondary: #656d76;
+ --text-tertiary: #8c959f;
+
+ --accent-primary: #2563eb;
+ --accent-hover: #1d4ed8;
+ --accent-light: #3b82f6;
+ --accent-dark: #1e3a8a;
+
+ --border-default: #d1d9e0;
+ --border-muted: #e7ecf0;
+
+ --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.08);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.12), 0 4px 6px -2px rgba(0, 0, 0, 0.08);
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.15), 0 10px 10px -5px rgba(0, 0, 0, 0.1);
+}
+
+/* ================================================
+ RESET & BASE
+ ================================================ */
+
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
@@ -18,62 +90,81 @@ time, mark, audio, video {
font: inherit;
vertical-align: baseline;
}
-/* HTML5 display-role reset for older browsers */
+
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
+
+* {
+ box-sizing: border-box;
+}
+
body {
- line-height: 1;
- position: absolute; top: 0;
+ line-height: 1.6;
+ position: absolute;
+ top: 0;
width: 100%;
+ height: 100%;
+ background-color: var(--bg-primary);
+ color: var(--text-primary);
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ transition: background-color 0.3s ease, color 0.3s ease;
}
+
ol, ul, li {
list-style: none;
}
+
blockquote, q {
quotes: none;
}
+
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
+
table {
border-collapse: collapse;
border-spacing: 0;
}
-/********************************** {{ grid }} *****/
+/* ================================================
+ GRID SYSTEM (Preserved)
+ ================================================ */
+
.blk {
width: 100%;
- margin: 0; padding: 0;
+ margin: 0;
+ padding: 0;
overflow: hidden;
}
+
.gutter {
position: relative;
width: 100%;
- max-width: 960;
+ max-width: 1200px;
margin: 0 auto;
- padding: 0 20;
- box-sizing: border-box;
+ padding: 0 24px;
}
+
.blk:after,
.gutter:after {
content: "";
display: table;
clear: both;
}
-@media (min-width: 400px) {
- /*
- .gutter { width: 85%; padding: 0 };
- */
-}
-.x1, .x2, .x3, .x4, .x5, .x6, .x7, .x8,
+.x1, .x2, .x3, .x4, .x5, .x6, .x7, .x8,
.x9, .x10, .x11, .x12, .x13, .x14, .x15, .x16 {
- display: block; float: left;
- margin: 0; padding: 0;
+ display: block;
+ float: left;
+ margin: 0;
+ padding: 0;
width: 100%;
}
@@ -82,258 +173,332 @@ table {
}
@media (min-width: 550px) {
- .x1 { width: 6.25%; }
- .x2 { width: 12.5%; }
- .x3 { width: 18.75%; }
- .x4 { width: 25%; }
- .x5 { width: 31.25%; }
- .x6 { width: 37.5%; }
- .x7 { width: 43.75%; }
- .x8 { width: 50%; }
- .x9 { width: 56.25%; }
- .x10 { width: 62.5%; }
- .x11 { width: 68.75%; }
- .x12 { width: 75%; }
- .x13 { width: 81.25%; }
- .x14 { width: 87.5%; }
- .x15 { width: 93.75%; }
- .x16 { width: 100%; }
-
- .l1 { margin-left: 6.25%; }
- .l2 { margin-left: 12.5%; }
- .l3 { margin-left: 18.75%; }
- .l4 { margin-left: 25%; }
- .l5 { margin-left: 31.25%; }
- .l6 { margin-left: 37.5%; }
- .l7 { margin-left: 43.75%; }
- .l8 { margin-left: 50%; }
- .l9 { margin-left: 56.25%; }
- .l10 { margin-left: 62.5%; }
- .l11 { margin-left: 68.75%; }
- .l12 { margin-left: 75%; }
- .l13 { margin-left: 81.25%; }
- .l14 { margin-left: 87.5%; }
- .l15 { margin-left: 93.75%; }
- .l16 { margin-left: 100%; }
-
- .r1 { margin-right: 6.25%; }
- .r2 { margin-right: 12.5%; }
- .r3 { margin-right: 18.75%; }
- .r4 { margin-right: 25%; }
- .r5 { margin-right: 31.25%; }
- .r6 { margin-right: 37.5%; }
- .r7 { margin-right: 43.75%; }
- .r8 { margin-right: 50%; }
- .r9 { margin-right: 56.25%; }
- .r10 { margin-right: 62.5%; }
- .r11 { margin-right: 68.75%; }
- .r12 { margin-right: 75%; }
- .r13 { margin-right: 81.25%; }
- .r14 { margin-right: 87.5%; }
- .r15 { margin-right: 93.75%; }
- .r16 { margin-right: 100%; }
-
-
- .c12 .x1 { width: 8.3333333%; }
- .c12 .x2 { width: 16.6666667%; }
- .c12 .x3 { width: 25%; }
- .c12 .x4 { width: 33.3333333%; }
- .c12 .x5 { width: 41.6666667%; }
- .c12 .x6 { width: 50%; }
- .c12 .x7 { width: 58.3333333%; }
- .c12 .x8 { width: 66.6666667%; }
- .c12 .x9 { width: 75%; }
- .c12 .x10 { width: 83.3333333%; }
- .c12 .x11 { width: 91.6666667%; }
- .c12 .x12 { width: 100%; }
- .c12 .x13,
- .c12 .x14,
- .c12 .x15,
- .c12 .x16 { width: 100%; }
-
- .c12 .l1 { margin-left: 8.3333333%; }
- .c12 .l2 { margin-left: 16.6666667%; }
- .c12 .l3 { margin-left: 25%; }
- .c12 .l4 { margin-left: 33.3333333%; }
- .c12 .l5 { margin-left: 41.6666667%; }
- .c12 .l6 { margin-left: 50%; }
- .c12 .l7 { margin-left: 58.3333333%; }
- .c12 .l8 { margin-left: 66.6666667%; }
- .c12 .l9 { margin-left: 75%; }
- .c12 .l10 { margin-left: 83.3333333%; }
- .c12 .l11 { margin-left: 91.6666667%; }
- .c12 .l12 { margin-left: 100%; }
- .c12 .l13,
- .c12 .l14,
- .c12 .l15,
- .c12 .l16 { margin-left: 0; }
-
- .c12 .r1 { margin-right: 8.3333333%; }
- .c12 .r2 { margin-right: 16.6666667%; }
- .c12 .r3 { margin-right: 25%; }
- .c12 .r4 { margin-right: 33.3333333%; }
- .c12 .r5 { margin-right: 41.6666667%; }
- .c12 .r6 { margin-right: 50%; }
- .c12 .r7 { margin-right: 58.3333333%; }
- .c12 .r8 { margin-right: 66.6666667%; }
- .c12 .r9 { margin-right: 75%; }
- .c12 .r10 { margin-right: 83.3333333%; }
- .c12 .r11 { margin-right: 91.6666667%; }
- .c12 .r12 { margin-right: 100%; }
- .c12 .r13,
- .c12 .r14,
- .c12 .r15,
- .c12 .r16 { margin-right: 0; }
-
- .c15 .x1 { width: 6.6666667%; }
- .c15 .x2 { width: 13.3333333%; }
- .c15 .x3 { width: 20%; }
- .c15 .x4 { width: 26.6666667%; }
- .c15 .x5 { width: 33.3333333%; }
- .c15 .x6 { width: 40%; }
- .c15 .x7 { width: 46.6666667%; }
- .c15 .x8 { width: 53.3333333%; }
- .c15 .x9 { width: 60%; }
- .c15 .x10 { width: 66.6666667%; }
- .c15 .x11 { width: 73.3333333%; }
- .c15 .x12 { width: 80%; }
- .c15 .x13 { width: 86.6666667%; }
- .c15 .x14 { width: 93.3333333%; }
- .c15 .x15,
- .c15 .x16 { width: 100%; }
-
- .c15 .l1 { margin-left: 6.6666667%; }
- .c15 .l2 { margin-left: 13.3333333%; }
- .c15 .l3 { margin-left: 20%; }
- .c15 .l4 { margin-left: 26.6666667%; }
- .c15 .l5 { margin-left: 33.3333333%; }
- .c15 .l6 { margin-left: 40%; }
- .c15 .l7 { margin-left: 46.6666667%; }
- .c15 .l8 { margin-left: 53.3333333%; }
- .c15 .l9 { margin-left: 60%; }
- .c15 .l10 { margin-left: 66.6666667%; }
- .c15 .l11 { margin-left: 73.3333333%; }
- .c15 .l12 { margin-left: 80%; }
- .c15 .l13 { margin-left: 86.6666667%; }
- .c15 .l14 { margin-left: 93.3333333%; }
- .c15 .l15,
- .c15 .l16 { margin-left: 0; }
-
- .c15 .r1 { margin-right: 6.6666667%; }
- .c15 .r2 { margin-right: 13.3333333%; }
- .c15 .r3 { margin-right: 20%; }
- .c15 .r4 { margin-right: 26.6666667%; }
- .c15 .r5 { margin-right: 33.3333333%; }
- .c15 .r6 { margin-right: 40%; }
- .c15 .r7 { margin-right: 46.6666667%; }
- .c15 .r8 { margin-right: 53.3333333%; }
- .c15 .r9 { margin-right: 60%; }
- .c15 .r10 { margin-right: 66.6666667%; }
- .c15 .r11 { margin-right: 73.3333333%; }
- .c15 .r15 { margin-right: 80%; }
- .c15 .r13 { margin-right: 86.6666667%; }
- .c15 .r14 { margin-right: 93.3333333%; }
- .c15 .r15,
- .c15 .r16 { margin-right: 0; }
-}
-
-
-
-body { height: 100%; }
-.pane { height: 100%; }
-.full { height: 100%; }
-.full .frontdoor { padding-top: 40px; }
-.story-sidebar nav,
-.hud > div {
- margin-top: 40px;
+ .x1 { width: 6.25%; }
+ .x2 { width: 12.5%; }
+ .x3 { width: 18.75%; }
+ .x4 { width: 25%; }
+ .x5 { width: 31.25%; }
+ .x6 { width: 37.5%; }
+ .x7 { width: 43.75%; }
+ .x8 { width: 50%; }
+ .x9 { width: 56.25%; }
+ .x10 { width: 62.5%; }
+ .x11 { width: 68.75%; }
+ .x12 { width: 75%; }
+ .x13 { width: 81.25%; }
+ .x14 { width: 87.5%; }
+ .x15 { width: 93.75%; }
+ .x16 { width: 100%; }
+
+ .c12 .x1 { width: 8.3333333%; }
+ .c12 .x2 { width: 16.6666667%; }
+ .c12 .x3 { width: 25%; }
+ .c12 .x4 { width: 33.3333333%; }
+ .c12 .x5 { width: 41.6666667%; }
+ .c12 .x6 { width: 50%; }
+ .c12 .x7 { width: 58.3333333%; }
+ .c12 .x8 { width: 66.6666667%; }
+ .c12 .x9 { width: 75%; }
+ .c12 .x10 { width: 83.3333333%; }
+ .c12 .x11 { width: 91.6666667%; }
+ .c12 .x12 { width: 100%; }
+}
+
+/* ================================================
+ SCROLLBAR
+ ================================================ */
+
+::-webkit-scrollbar {
+ width: 12px;
+ height: 12px;
}
-body { font-family: sans-serif; }
+::-webkit-scrollbar-track {
+ background: var(--bg-secondary);
+}
-#loading {
- display: block;
- max-width: 240px;
- margin: 3em auto 1em auto;
+::-webkit-scrollbar-thumb {
+ background: var(--bg-tertiary);
+ border-radius: 6px;
+ border: 2px solid var(--bg-secondary);
}
-.top-bar {
- background-color: #0071BC;
- color: #fff;
- box-shadow: 0px 4px 5px rgba(0,0,0,0.25);
+::-webkit-scrollbar-thumb:hover {
+ background: var(--border-default);
+}
- font: normal normal normal 15px/15px sans-serif;
+/* ================================================
+ TOP BAR
+ ================================================ */
+.top-bar {
+ background-color: var(--bg-secondary);
+ color: var(--text-primary);
+ box-shadow: var(--shadow-md);
+ border-bottom: 1px solid var(--border-default);
+ font: normal 14px/1 sans-serif;
position: fixed;
- top: 0px; let: 0px;
+ top: 0;
+ left: 0;
width: 100%;
+ height: 48px;
z-index: 100;
+ backdrop-filter: blur(10px);
+ display: flex;
+ align-items: center;
+ padding: 0 12px;
+ gap: 4px;
+ /* no overflow:hidden — dropdown must escape the bar */
+}
+
+.top-bar > * {
+ display: block;
+ padding: 0 8px;
+ flex-shrink: 0;
+}
+
+.top-bar .cli {
+ font-size: 16px;
+ padding: 0 4px;
+ line-height: 1;
+}
+
+.top-bar h1 {
+ font-weight: 600;
+ font-size: 17px;
+ letter-spacing: -0.3px;
+ white-space: nowrap;
+ flex: 1; /* absorbs spare space, pushes account link to far right */
+ min-width: 0;
+ line-height: 1;
+ padding: 0 4px;
+}
+
+.top-bar h1 span {
+ font-weight: 400;
+ font-size: 11px;
+ vertical-align: middle;
+ color: var(--accent-light);
+ opacity: 0.8;
+}
+
+.top-bar a {
+ text-decoration: none;
+ color: inherit;
+ transition: color 0.2s ease;
+}
+
+.top-bar a:hover {
+ color: var(--accent-light);
+}
+
+.top-bar a[rel=account] {
+ margin-left: 0;
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 5px 12px;
+ border-radius: var(--radius-md);
+ background-color: var(--bg-tertiary);
+ border: 1px solid var(--border-default);
+ font-size: 13px;
+ transition: all 0.2s ease;
+ margin: 6px 0;
+ line-height: 1;
+}
+
+.top-bar a[rel=account]::after {
+ content: '';
+ display: inline-block;
+ border: 4px solid transparent;
+ border-top-color: currentColor;
+ margin-top: 4px;
+ flex-shrink: 0;
+}
+
+.top-bar a[rel=account]:hover {
+ background-color: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ color: var(--text-primary);
+}
+
+/* ================================================
+ ACCOUNT DROPDOWN
+ ================================================ */
+
+.top-bar .flyout {
+ display: none;
+ position: fixed;
+ top: 48px;
+ right: 0;
+ min-width: 260px;
+ background-color: var(--bg-card);
+ border: 1px solid var(--border-default);
+ border-top: none;
+ border-radius: 0 0 var(--radius-lg) var(--radius-lg);
+ box-shadow: var(--shadow-xl);
+ z-index: 200;
+ overflow: hidden;
+}
+
+.top-bar .flyout .menu {
+ padding: 4px 0;
+}
+
+.top-bar .flyout .header {
+ padding: 10px 16px 6px;
+ font-size: 12px;
+ font-weight: 700;
+ color: var(--text-tertiary);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ line-height: 1.4;
+}
+
+.top-bar .flyout .header span {
+ display: inline-block;
+ background-color: var(--bg-elevated);
+ border: 1px solid var(--border-default);
+ border-radius: 4px;
+ padding: 1px 7px;
+ font-size: 11px;
+ font-weight: 500;
+ color: var(--text-secondary);
+ text-transform: none;
+ letter-spacing: 0;
+ margin-left: 4px;
+ vertical-align: middle;
+}
+
+.top-bar .flyout .divider {
+ height: 1px;
+ background-color: var(--border-default);
+ margin: 4px 0;
+}
+
+.top-bar .flyout a.dropdown,
+.top-bar .flyout span.dropdown {
+ display: block;
+ padding: 9px 16px;
+ font-size: 13px;
+ color: var(--text-primary);
+ text-decoration: none;
+ transition: background-color 0.15s ease, color 0.15s ease;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.top-bar .flyout a.dropdown:hover {
+ background-color: var(--bg-tertiary);
+ color: var(--accent-light);
+}
+
+/* Current active tenant */
+.top-bar .flyout a.dropdown.current\.tenant {
+ color: var(--accent-primary);
+ font-weight: 600;
+ background-color: rgba(59, 130, 246, 0.08);
+}
+
+.top-bar .flyout a.dropdown.current\.tenant::before {
+ content: '✓ ';
+ opacity: 0.8;
+}
+
+/* "No tenants" placeholder */
+.top-bar .flyout span.dropdown.odd {
+ color: var(--text-tertiary);
+ font-style: italic;
+ cursor: default;
+}
+
+/* Sign out gets a subtle danger hint on hover */
+.top-bar .flyout a.dropdown[href="#!/logout"]:hover {
+ color: var(--error);
+ background-color: rgba(239, 68, 68, 0.06);
+}
+
+/* ================================================
+ LOADING
+ ================================================ */
+
+#loading {
+ display: block;
+ max-width: 240px;
+ margin: 3em auto 1em auto;
}
-.top-bar > * { display: block; padding: 7px; }
-.top-bar .cli { float: left; }
-.top-bar .cli:nth-child(2) { padding: 7px 10px 7px 0; }
-.top-bar h1 { float: left; }
-.top-bar a { text-decoration: none; color: inherit; }
-.top-bar a[rel=account] { float: right; }
-.top-bar h1 { font-weight: bold; }
-.top-bar h1 span { font-weight: normal; font-size: 10px; vertical-align: text-top }
+/* ================================================
+ FRONTDOOR / LOGIN
+ ================================================ */
.frontdoor {
- background: #4d4d4d url(/i/shield-logo.svg) no-repeat 30% 60%;
- background-size: auto 90vh;
- box-sizing: border-box;
+ background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
position: fixed;
height: 100%;
width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
+
.frontdoor > div {
- display: block;
width: 600px;
- margin: 10vh auto;
+ max-width: 90%;
}
-.frontdoor h1,
-.frontdoor .dialog { width: 580px; }
+
.frontdoor h1 {
- font-size: 40pt;
- font-weight: bold;
- color: white;
- text-shadow: 3px 3px 4px #333;
+ font-size: 48px;
+ font-weight: 700;
+ color: var(--text-primary);
text-transform: uppercase;
+ margin-bottom: 2rem;
+ letter-spacing: -1.5px;
}
+
.frontdoor h1 span {
- color: #8CC63F;
- font-size: 16pt;
- padding-left: 0.3em;
+ color: var(--accent-primary);
+ font-size: 18px;
+ padding-left: 0.5em;
+ font-weight: 400;
}
+
.frontdoor h2 {
- font-size: 12pt;
- font-weight: bold;
- white-space: pre;
+ font-size: 14px;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ color: var(--text-secondary);
}
+
.frontdoor .dialog {
- background-color: #E6E6E6;
- border: none;
- border-radius: 10px;
- padding: 20px;
- box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
+ background-color: var(--bg-card);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+ padding: 32px;
+ box-shadow: var(--shadow-xl);
overflow: hidden;
}
-.frontdoor .dialog > img.highlight {
- display: block;
- margin: 1em;
- float: right;
-}
+
.frontdoor .dialog p {
- font-size: 12pt;
- line-height: 1.1em;
- margin: 0 0 1em 0;
+ font-size: 14px;
+ line-height: 1.6;
+ margin: 0 0 1.5em 0;
+ color: var(--text-secondary);
+}
+
+/* Login Specific */
+#login > div.local-only .dialog {
+ width: 400px;
+ max-width: 90%;
}
-#login > div.local-only .dialog { width: 400px; }
#login .motd {
margin: 0 0 2em 0;
- border-bottom: 1px solid #ccc;
+ padding-bottom: 1em;
+ border-bottom: 1px solid var(--border-default);
}
+
#login .oauth2,
#login .local {
width: 50%;
@@ -341,119 +506,139 @@ body { font-family: sans-serif; }
box-sizing: border-box;
float: left;
}
-#login .oauth2 { width: 45%; padding-right: 10px; }
-#login .local { width: 55%; padding-left: 20px; border-left: 1px solid #aaa; }
-#login > div.local-only .local { width: 100%; padding: 0; border: none; }
+
+#login .oauth2 {
+ width: 45%;
+ padding-right: 20px;
+}
+
+#login .local {
+ width: 55%;
+ padding-left: 20px;
+ border-left: 1px solid var(--border-default);
+}
+
+#login > div.local-only .local {
+ width: 100%;
+ padding: 0;
+ border: none;
+}
+
+#login .oauth2 ul {
+ margin: 20px 0;
+}
#login .oauth2 li a {
display: block;
- font-size: 12pt;
- background-color: #0071bc;
- color: #fff;
- padding: 8px 10px;
+ font-size: 14px;
+ background-color: var(--accent-primary);
+ color: white;
+ padding: 12px 16px;
border: none;
+ border-radius: var(--radius-md);
margin-bottom: 12px;
- margin-right: 6px;
cursor: pointer;
text-decoration: none;
+ text-align: center;
+ transition: all 0.2s ease;
+ font-weight: 500;
}
-#login .oauth2 ul {
- margin: 20px 0;
+
+#login .oauth2 li a:hover {
+ background-color: var(--accent-hover);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md);
}
+
#login .local a {
- color: #0071bc;
+ color: var(--accent-primary);
text-decoration: none;
+ transition: color 0.2s ease;
}
-#login .local p.divert {
- font-size: 10pt;
- margin-top: 0.4em;
- margin-bottom: 1em;
+
+#login .local a:hover {
+ color: var(--accent-light);
}
+
#login .local .ctl {
width: 100%;
- margin-bottom: 0.5em;
+ margin-bottom: 16px;
}
+
#login .local label {
- font-weight: normal;
+ font-weight: 500;
+ font-size: 14px;
+ margin-bottom: 6px;
+ display: block;
+ color: var(--text-primary);
}
+
#login .local input[type=text],
#login .local input[type=password] {
- border: none;
+ border: 1px solid var(--border-default);
width: 100%;
- font-size: 14pt;
- background: linear-gradient(to bottom, #404040 0%, #4d4d4d 100%);
- color: #fff;
-
- box-sizing: border-box;
- padding: 8px;
+ font-size: 14px;
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ padding: 12px;
+ border-radius: var(--radius-md);
+ transition: all 0.2s ease;
}
-#login .local .cbdark {
- width: 16px;
- position: relative;
+
+#login .local input[type=text]:focus,
+#login .local input[type=password]:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
+ background-color: var(--bg-elevated);
}
-#login .local .cbdark label {
- width: 16px;
- height: 16px;
+
+#login .local button {
+ display: block;
+ font-size: 14px;
+ background-color: var(--accent-primary);
+ color: white;
+ padding: 12px 24px;
+ border: none;
+ border-radius: var(--radius-md);
cursor: pointer;
- position: absolute;
- left: 0px; top: 0px;
- background: linear-gradient(to bottom, #404040 0%, #4d4d4d 100%);
- border-radius: 4px;
- box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,.4);
-}
-#login .local .cbdark label::after {
- content: '';
- width: 8px;
- height: 4px;
- position: absolute;
- top: 4px;
- left: 4px;
- border: 3px solid #fcfff4;
- border-top: none;
- border-right: none;
- background: transparent;
- opacity: 0;
- transform: rotate(-45deg);
-}
-#login .local .cbdark label:hover::after {
- opacity: 0.3;
-}
-#login .local .cbdark input {
- visibility: hidden;
-}
-#login .local .cbdark input:checked + label:after {
- opacity: 1;
-}
-#login .local a.forgotpw {
- font-size: 10pt;
float: right;
+ transition: all 0.2s ease;
+ font-weight: 500;
+}
+
+#login .local button:hover {
+ background-color: var(--accent-hover);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md);
}
+
#login .local .errors {
- color: crimson;
+ color: var(--error);
font-size: 13px;
+ margin-top: 8px;
}
-#login .local button {
- display: block;
- font-size: 12pt;
- background-color: #0071bc;
- color: #fff;
- padding: 8px 10px;
- border: none;
- margin-bottom: 6px;
- margin-right: 6px;
- cursor: pointer;
+
+#login .local a.forgotpw {
+ font-size: 12px;
float: right;
+ margin-top: 8px;
}
-
+/* Initialize (Similar to Login) */
#initialize {
- overflow: scroll;
+ overflow-y: auto;
+}
+
+#initialize > div.setpass-only .dialog {
+ width: 400px;
+ max-width: 90%;
}
-#initialize > div.setpass-only .dialog { width: 400px; }
#initialize p.motd {
margin: 0 0 2em 0;
}
+
#initialize .restore,
#initialize .setpass {
width: 50%;
@@ -461,2203 +646,2269 @@ body { font-family: sans-serif; }
box-sizing: border-box;
float: left;
}
-#initialize .restore { width: 45%; padding-right: 10px; }
-#initialize .setpass { width: 55%; padding-left: 20px; }
-#initialize > div.setpass-only .setpass { width: 100%; padding: 0; border: none; }
-#initialize .restore-form .restore { width: 100%; padding-right: 10px; }
-#initialize .setpass-form .setpass { width: 100%; padding-left: 20px; }
-#initialize .restore li a {
- display: block;
- font-size: 12pt;
- background-color: #0071bc;
- color: #fff;
- padding: 8px 10px;
+#initialize .restore {
+ width: 45%;
+ padding-right: 10px;
+}
+
+#initialize .setpass {
+ width: 55%;
+ padding-left: 20px;
+}
+
+#initialize > div.setpass-only .setpass {
+ width: 100%;
+ padding: 0;
border: none;
- margin-bottom: 12px;
- margin-right: 6px;
- cursor: pointer;
- text-decoration: none;
}
-#initialize .restore ul {
- margin: 20px 0;
+
+#initialize .setpass input[type=text],
+#initialize .setpass input[type=password],
+#initialize .restore input[type=text],
+#initialize .restore input[type=password],
+#initialize .restore textarea {
+ border: 1px solid var(--border-default);
+ width: 100%;
+ font-size: 14px;
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ padding: 12px;
+ border-radius: var(--radius-md);
+ transition: all 0.2s ease;
}
-#initialize .setpass a {
- color: #0071bc;
- text-decoration: none;
+#initialize .restore textarea {
+ font-size: 12px;
+ height: 15em;
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
}
+#initialize button,
+#initialize .restore li a,
#initialize .file-upload {
display: block;
- font-size: 12pt;
- background-color: #0071bc;
- color: #fff;
- padding: 8px 10px;
+ font-size: 14px;
+ background-color: var(--accent-primary);
+ color: white;
+ padding: 12px 16px;
border: none;
- margin-top: 10px;
- margin-bottom: 10px;
- margin-right: 65%;
+ border-radius: var(--radius-md);
cursor: pointer;
- float: right;
+ text-decoration: none;
+ transition: all 0.2s ease;
+ font-weight: 500;
+ text-align: center;
}
-#initialize .setpass p.divert {
- font-size: 10pt;
- margin-top: 0.4em;
- margin-bottom: 1em;
-}
-#initialize .setpass .ctl {
- width: 100%;
- margin-bottom: 0.5em;
+#initialize button:hover,
+#initialize .restore li a:hover,
+#initialize .file-upload:hover {
+ background-color: var(--accent-hover);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md);
}
-#initialize .setpass label {
- font-weight: normal;
+
+#initialize .errors {
+ color: var(--error);
+ font-size: 13px;
+ margin-top: 8px;
}
-#initialize .setpass input[type=text],
-#initialize .setpass input[type=password] {
- border: none;
- width: 100%;
- font-size: 14pt;
- background: linear-gradient(to bottom, #404040 0%, #4d4d4d 100%);
- color: #fff;
+/* ================================================
+ BANNERS
+ ================================================ */
- box-sizing: border-box;
- padding: 8px;
-}
-#initialize .setpass .cbdark {
- width: 16px;
- position: relative;
-}
-#initialize .setpass .cbdark label {
- width: 16px;
- height: 16px;
- cursor: pointer;
- position: absolute;
- left: 0px; top: 0px;
- background: linear-gradient(to bottom, #404040 0%, #4d4d4d 100%);
- border-radius: 4px;
- box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,.4);
-}
-#initialize .setpass .cbdark label::after {
- content: '';
- width: 8px;
- height: 4px;
- position: absolute;
- top: 4px;
- left: 4px;
- border: 3px solid #fcfff4;
- border-top: none;
- border-right: none;
- background: transparent;
- opacity: 0;
- transform: rotate(-45deg);
-}
-#initialize .setpass .cbdark label:hover::after {
- opacity: 0.3;
-}
-#initialize .setpass .cbdark input {
- visibility: hidden;
-}
-#initialize .setpass .cbdark input:checked + label:after {
- opacity: 1;
-}
-#initialize .setpass a.forgotpw {
- font-size: 10pt;
- float: right;
-}
-#initialize .setpass .errors {
- color: crimson;
- font-size: 13px;
-}
-#initialize .setpass button {
- display: block;
- font-size: 12pt;
- background-color: #0071bc;
+.banner-top p {
color: #fff;
- padding: 8px 10px;
- border: none;
- margin-bottom: 6px;
- margin-right: 6px;
- cursor: pointer;
- float: right;
+ background-color: var(--error);
+ box-shadow: var(--shadow-md);
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 100;
+ padding: 12px 0;
+ text-align: center;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+ font-size: 14px;
+ font-weight: 500;
}
-
-
-
-#initialize .restore a {
- color: #0071bc;
+.banner-top p a {
+ display: inline-block;
text-decoration: none;
-}
-#initialize .restore p.restore_divert {
- font-size: 10pt;
- margin-top: 0.4em;
- margin-bottom: 3em;
-}
-#initialize .restore .ctl {
- width: 100%;
- margin-bottom: 0.5em;
+ border-bottom: 1px dotted #fff;
+ color: #fff;
+ margin-left: 1em;
+ opacity: 0.9;
}
-#initialize .restore label .restore-file {
- width: 75%;
- font-weight: normal;
-}
-#initialize .restore label {
- width: 75%;
- font-weight: normal;
+.banner-top p.info {
+ background-color: var(--success);
}
-#initialize .restore input[type=file] {
- display: none;
+.banner-top p.error {
+ background-color: var(--error);
}
-#initialize .restore input[type=text],
-#initialize .restore input[type=password],
-#initialize .restore textarea {
- width: 100%;
- font-size: 14pt;
- background: linear-gradient(to bottom, #404040 0%, #4d4d4d 100%);
- color: #fff;
- box-sizing: border-box;
- padding: 8px;
+.banner-top p.progress {
+ background-color: var(--info);
}
-#initialize .restore textarea {
- font-size: 8pt;
- border: none;
- height: 15em;
+
+/* ================================================
+ SIDEBAR
+ ================================================ */
+
+.story-sidebar {
+ background-color: var(--bg-secondary);
+ color: var(--text-primary);
+ box-shadow: var(--shadow-lg);
+ border-right: 1px solid var(--border-default);
+ position: fixed;
+ top: 48px;
+ left: 0;
+ z-index: 80;
+ height: calc(100% - 48px);
+ width: 280px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ transition: width 0.25s ease;
}
-#initialize .restore .cbdark {
- width: 16px;
- position: relative;
+
+.story-sidebar.collapsed {
+ width: 56px;
}
-#initialize .restore .cbdark label {
- width: 16px;
- height: 16px;
+
+/* Toggle button — fixed, centered on sidebar right edge, ~24px below navbar */
+.sidebar-toggle {
+ position: fixed;
+ top: 58px; /* 48px navbar + 24px into sidebar - 14px half-button */
+ left: 266px; /* 280px sidebar - 14px half-button = center on right edge */
+ width: 28px;
+ height: 28px;
+ padding: 0;
+ border-radius: 50%;
+ background-color: var(--bg-secondary);
+ border: 1px solid var(--border-default);
+ color: var(--text-secondary);
+ font-size: 11px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
cursor: pointer;
- position: absolute;
- left: 0px; top: 0px;
- background: linear-gradient(to bottom, #404040 0%, #4d4d4d 100%);
- border-radius: 4px;
- box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,.4);
+ transition: left 0.25s ease, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
+ z-index: 90; /* below top-bar (100) but above sidebar (80) */
+ box-shadow: var(--shadow-sm);
}
-#initialize .file-upload button {
- margin: auto;
-}
-#initialize .restore .cbdark label::after {
- content: '';
- width: 8px;
- height: 4px;
- position: absolute;
- top: 4px;
- left: 4px;
- border: 3px solid #fcfff4;
- border-top: none;
- border-right: none;
- background: transparent;
- opacity: 0;
- transform: rotate(-45deg);
+
+.sidebar-toggle:hover {
+ background-color: var(--accent-primary);
+ border-color: var(--accent-primary);
+ color: #fff;
+ transform: none;
+ box-shadow: var(--shadow-md);
}
-#initialize .restore .cbdark label:hover::after {
- opacity: 0.3;
+
+body.sidebar-collapsed .sidebar-toggle {
+ left: 42px; /* 56px - 14px */
}
-#initialize .restore .cbdark input {
- visibility: hidden;
+
+body.sidebar-collapsed .sidebar-toggle i {
+ transform: rotate(180deg);
}
-#initialize .restore .cbdark input:checked + label:after {
- opacity: 1;
+
+.sidebar-toggle i {
+ transition: transform 0.25s ease;
}
-#initialize .restore a.forgotpw {
- font-size: 10pt;
- float: right;
+
+.hud > div {
+ margin-top: 48px;
}
-#initialize .restore .errors {
- color: crimson;
- font-size: 13px;
+
+.story-sidebar li {
+ padding: 0;
+ border-bottom: 1px solid var(--border-default);
+ transition: background-color 0.2s ease;
+ overflow: hidden;
}
-#initialize .restore button {
- display: block;
- font-size: 12pt;
- background-color: #0071bc;
- color: #fff;
- padding: 8px 10px;
- border: none;
- margin-bottom: 6px;
- margin-right: 6px;
- cursor: pointer;
- float: right;
+
+.story-sidebar li:hover {
+ background-color: var(--bg-tertiary);
}
-.banner-top p {
- color: #fff;
- background-color: #FF1D25;
- box-shadow: 0px 4px 5px rgba(0,0,0,0.25);
+.story-sidebar li a {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 14px 20px;
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--accent-primary);
+ text-decoration: none;
+ transition: color 0.2s ease;
+ white-space: nowrap;
+}
- position: fixed;
- top: 0px; left: 0; right: 0;
- z-index: 100;
+.story-sidebar li a:hover {
+ color: var(--accent-light);
+}
- padding: 7px 0 9px 0;
+.sidebar-icon {
+ font-size: 15px;
+ width: 16px;
text-align: center;
- border-top: 1px solid #000;
- border-bottom: 1px solid #000;
-}
-.banner-top p a {
- display: inline-block;
- text-decoration: none;
- border-bottom: 1px dotted #fff;
- color: #fff;
- font-size: 80%;
- margin-left: 1em;
+ flex-shrink: 0;
}
-.banner-top p.info { color: #fff; background-color: #729849; }
-.banner-top p.error { color: #fff; background-color: #ff1d25; }
-.banner-top p.progress { color: #fff; background-color: #0071bc; }
-
-.story-sidebar {
- background-color: #F2F2F2;
- color: #000;
- box-shadow: 4px 0px 5px rgba(0,0,0,0.25);
- position: fixed;
- top: 0px; left: 0px;
- z-index: 80;
- height: 100%;
- width: 25%;
+.sidebar-label {
+ overflow: hidden;
+ transition: opacity 0.15s ease, max-width 0.25s ease;
+ white-space: nowrap;
}
-.story-sidebar li {
- padding: 15px;
- border-bottom: 1px solid #B3B3B3;
+.story-sidebar li p.sidebar-desc {
+ font-size: 12px;
+ margin: 0;
+ padding: 0 20px 12px 48px;
+ color: var(--text-secondary);
+ line-height: 1.5;
+ transition: opacity 0.15s ease, max-height 0.25s ease;
+ max-height: 6em;
+ overflow: hidden;
}
-.story-sidebar li a {
- font-size: 18.5px;
- line-height: 22.5px;
- font-weight: bold;
- color: #0071BC;
- text-decoration: none;
+
+/* Collapsed: hide labels and descriptions */
+.story-sidebar.collapsed .sidebar-label,
+.story-sidebar.collapsed li p.sidebar-desc {
+ opacity: 0;
+ max-width: 0;
+ max-height: 0;
+ padding: 0;
+ pointer-events: none;
}
-.story-sidebar li p {
- font-size: 14px;
- margin: 0 0 0 7px;
+
+/* Collapsed: center the icon */
+.story-sidebar.collapsed li a {
+ justify-content: center;
+ padding: 16px 0;
+ gap: 0;
}
footer {
position: fixed;
bottom: 0;
- padding: 4px;
- background-color: #f2f2f2;
+ width: 280px;
+ padding: 12px;
+ background-color: var(--bg-secondary);
+ border-top: 1px solid var(--border-default);
+ overflow: hidden;
+ transition: width 0.25s ease;
+}
+
+.sidebar-collapsed footer {
+ width: 56px;
}
footer a {
display: inline-block;
width: 20px;
+ opacity: 0.7;
+ transition: opacity 0.2s ease;
+}
+
+footer a:hover {
+ opacity: 1;
}
+
footer a object,
footer a img {
width: 100%;
}
-footer p {
- font-size: 9pt;
+
+footer p.sidebar-label {
+ font-size: 11px;
+ color: var(--text-tertiary);
+ white-space: nowrap;
+ overflow: hidden;
+ transition: opacity 0.15s ease, max-height 0.25s ease;
+ max-height: 2em;
}
-.pane {
- width: 75%;
- margin-left: 25%;
+.sidebar-collapsed footer p.sidebar-label {
+ opacity: 0;
+ max-height: 0;
+ padding: 0;
}
-.hud {
- background-color: #4D4D4D;
- color: #fff;
- xheight: 240px;
+/* ================================================
+ MAIN PANE
+ ================================================ */
- z-index: 60;
+.pane {
+ width: calc(100% - 280px);
+ margin-left: 280px;
+ height: 100%;
+ transition: width 0.25s ease, margin-left 0.25s ease;
}
-/* 24px = 15px (standard margin) + 9px (inner padding on .prot / .health) */
-.hud .inst { margin: 24px; line-height: 18.5px; }
-.hud .inst .shield { font-size: 22.5px; line-height: 24px; font-weight: bold; }
-.hud .inst .shield span { font-size: 15px; color: #29ABE2; }
-.hud .inst .env { font-weight: bold; }
-.hud .health,
-.hud .prot {
- background-color: #1A1A1A;
- color: #fff;
- border-radius: 7px;
- padding: 9px;
- margin: 15px;
-
- font-size: 15px;
+.sidebar-collapsed .pane {
+ width: calc(100% - 56px);
+ margin-left: 56px;
}
-.hud .health .fill,
-.hud .prot .fill {
- height: 80px;
+
+.full {
+ height: 100%;
}
-.hud .health { line-height: 25px; }
-.hud .health object { width: 18px; height: 18px; display: inline-block; vertical-align: middle; }
+.full .frontdoor {
+ padding-top: 60px;
+}
-.hud .prot { line-height: 18.5px; }
-.hud .prot li span { float: right; }
-.hud .prot h3 { font-weight: bold; }
-.hud .prot ul { padding-left: 7px; }
+/* ================================================
+ HUD / DASHBOARD
+ ================================================ */
-.hud .ok span { color: #8CC63F; }
-.hud .warn span { color: #FCEE21; }
-.hud .fail span { color: #FF6161; text-transform: uppercase }
+.hud {
+ background-color: var(--bg-secondary);
+ background-image: url('/bg.jpg');
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ color: var(--text-primary);
+ padding: 24px 0;
+ position: relative;
+}
-.nav {
- background-color: #000;
- color: #fff;
- height: 40px;
+/* Overlay so the cards stay readable over the photo */
+.hud::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.55);
+ pointer-events: none;
+}
- box-shadow: 0px 4px 5px rgba(0,0,0,0.25);
+[data-theme="light"] .hud::before {
+ background: rgba(255, 255, 255, 0.6);
+}
+/* Cards and content sit above the overlay */
+.hud > * {
position: relative;
- z-index: 40;
+ z-index: 1;
+}
- text-align: right;
+.hud .inst {
+ margin: 24px;
+ line-height: 1.6;
}
-.nav a {
- color: inherit;
- text-decoration: none;
- font-weight: bold;
+
+.hud .inst .shield {
+ font-size: 24px;
+ font-weight: 700;
+ margin-bottom: 8px;
}
-.nav .current a { color: #FFFF00; }
-.nav li {
- display: inline-block;
- padding-right: 22.5px;
- line-height: 40px;
+
+.hud .inst .shield span {
+ font-size: 16px;
+ color: var(--accent-primary);
}
-.nav.sticky {
- display: none;
- position: fixed;
- top: 29px;
- width: 75%;
- z-index: 99;
+.hud .inst .env {
+ font-weight: 600;
+ color: var(--text-secondary);
+ font-size: 14px;
}
-.nav.sticky.on { display: block; }
-.gutter { padding: 1.5em; }
-.gutter.blk { width: auto; }
+.hud .health,
+.hud .prot {
+ background-color: var(--bg-card);
+ color: var(--text-primary);
+ border-radius: var(--radius-lg);
+ padding: 20px;
+ margin: 20px;
+ border: 1px solid var(--border-default);
+ transition: all 0.2s ease;
+}
-.field .card {
- background-color: #F2F2F2;
- box-shadow: 4px 4px 5px rgba(0,0,0,0.25);
+.hud .health:hover,
+.hud .prot:hover {
+ border-color: var(--border-default);
+ box-shadow: var(--shadow-md);
+ transform: translateY(-2px);
}
-.field .shadow.card {
- color: #999;
- font-size: 18pt;
- text-align: center;
- line-height: 3em;
- opacity: 0.4;
- cursor: pointer;
+.hud .health h3,
+.hud .prot h3 {
+ font-weight: 600;
+ margin-bottom: 12px;
+ font-size: 15px;
}
-.field .shadow.card:hover {
- opacity: 0.9;
+
+.hud .prot ul {
+ padding-left: 0;
}
-.field .shadow.card a {
- display: block;
+
+.hud .prot li {
+ padding: 8px 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
}
-.field .card h3 {
- font-size: 18px;
- font-weight: bold;
+
+.hud .health ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
}
-.no-data {
- font-style: italic;
- text-align: center;
- opacity: 0.5;
- font-size: 120%;
- padding: 2.5em 0 4em 0;
+.hud .health li {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 0;
+ border-bottom: 1px solid var(--border-muted);
+ font-size: 14px;
+ color: var(--text-secondary);
+ line-height: 1.4;
}
-.card,
-.summary {
- padding: 1%;
- width: 42%;
- margin: 2% 0 0 2%;
- float: left;
+.hud .health li:last-child {
+ border-bottom: none;
+ padding-bottom: 0;
}
-.store .summary {
- width: 100%;
- margin: 1em;
- float: none;
- font-style: italic;
+
+.hud .health li:first-child {
+ padding-top: 0;
}
-table.lean td.name > .tag,
-.store h2 .tag {
- background-color: #0071bcaa;
- color: #fff;
- border-radius: 4px;
- font-size: 8pt;
- font-weight: bold;
- padding: 4px 8px;
- display: inline;
- position: relative;
- top: -3px;
- left: 3px;
+.hud .health li object {
+ width: 22px;
+ height: 22px;
+ flex-shrink: 0;
}
-.card:nth-child(2n+1) {
- clear: both;
- margin: 2% 2% 2% 0;
+
+.hud .health li.ok {
+ color: var(--text-primary);
}
-.card > a { color: inherit; text-decoration: none; }
-.card {
- position: relative;
+
+.hud .health li.fail {
+ color: var(--text-primary);
}
-.card .type {
- font-size: 7.5pt;
- font-weight: bold;
- text-transform: uppercase;
- position: absolute;
- left: 8px; bottom: 4px;
+
+.hud .ok span {
+ color: var(--success);
+ font-weight: 600;
}
-.card .details {
- font-size: 14px;
- padding: 7px;
+.hud .warn span {
+ color: var(--warning);
+ font-weight: 600;
}
-.card .details strong {
- font-weight: bold;
+
+.hud .fail span {
+ color: var(--error);
+ font-weight: 600;
+ text-transform: uppercase;
}
-.card img {
- width: 24px;
- float: right;
+
+/* ================================================
+ TOP-BAR NAVIGATION
+ ================================================ */
+
+.top-bar .top-nav {
+ display: flex;
+ align-items: stretch;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ gap: 0;
}
-.card.fail img { width: 36px; }
-.card.fail h3 { color: #FF1D25; }
-.card .graph {
- height: 30px;
+.top-bar .top-nav li {
+ display: flex;
+ align-items: stretch;
position: relative;
- margin-bottom: 2em;
}
-.card .graph:last-child {
- margin-bottom: 0em;
+
+.top-bar .top-nav li a {
+ display: flex;
+ align-items: center;
+ padding: 0 14px;
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--text-secondary);
+ text-decoration: none;
+ white-space: nowrap;
+ transition: color 0.15s ease, background-color 0.15s ease;
+ border-radius: 0;
+}
+
+.top-bar .top-nav li a:hover {
+ color: var(--text-primary);
+ background-color: rgba(255,255,255,0.05);
}
-.card .from,
-.card .to {
- background-color: #0071BC;
- color: #fff;
- border-radius: 7px;
- padding: 7px;
- position: relative;
- z-index: 50;
-}
-.card .graph.fail > div { background-color: #FF1D25; }
-.card .from { float: left; }
-.card .to { float: right; }
-.card .bar {
- background-color: #0071BC;
- height: 4px;
- width: 100%;
+
+.top-bar .top-nav li.current a {
+ color: var(--text-primary);
+ font-weight: 600;
+}
+
+.top-bar .top-nav li.current::after {
+ content: '';
position: absolute;
- top: 50%;
- margin-top: -2px;
- z-index: 49;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 2px;
+ background-color: var(--accent-primary);
+ border-radius: 2px 2px 0 0;
}
-.summary .notes,
-.card .notes {
- font-size: 14px;
- padding: 1em;
- font-style: italic;
- line-height: 1.2em;
+
+/* ================================================
+ CONTENT & CARDS
+ ================================================ */
+
+.gutter {
+ padding: 2rem;
}
-.card .notes strong {
- font-weight: bold;
+
+.gutter.blk {
+ width: auto;
}
-.card .notes .no-data {
- font-size: inherit;
- padding: 0;
+.gutter > h2 {
+ font-size: 28px;
+ font-weight: 700;
+ clear: both;
+ line-height: 1.3;
+ margin: 1rem 0;
+ color: var(--text-primary);
}
-.summary h2 {
+.gutter > h3 {
+ font-size: 22px;
+ font-weight: 600;
+ margin: 1rem 0;
+}
+
+.gutter > h4 {
font-size: 18px;
- font-weight: bold;
+ font-weight: 600;
+ margin: 1rem 0;
}
-.summary p {
- margin: 0.5em;
+
+.field p {
+ margin: 1em 0;
+ line-height: 1.6;
+ color: var(--text-secondary);
}
-.system.view h1 {
- font-size: 36px;
- font-weight: bold;
- clear: both;
- margin-bottom: 1em;
+.field p a {
+ text-decoration: none;
+ border-bottom: 1px solid var(--accent-primary);
+ color: var(--accent-primary);
+ transition: color 0.2s ease;
}
-.system.view h2 span {
- font-size: 18px;
- color: #0071bc;
- display: block;
+
+.field p a:hover {
+ color: var(--accent-light);
}
-.system.view h2 img {
- height: 0.9em;
+
+.field .card {
+ background-color: var(--bg-card);
+ box-shadow: var(--shadow-md);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+ transition: all 0.2s ease;
}
-.lean img { width: 16px; }
-.lean .name {
- font-size: 18px;
- font-weight: bold;
- white-space: nowrap
+.field .card:hover {
+ box-shadow: var(--shadow-lg);
+ transform: translateY(-2px);
+ border-color: var(--border-default);
}
-.lean .name a {
- text-decoration: none;
- color: inherit;
+
+.field .shadow.card {
+ color: var(--text-tertiary);
+ font-size: 16px;
+ text-align: center;
+ line-height: 3em;
+ opacity: 0.6;
+ cursor: pointer;
+ background-color: var(--bg-tertiary);
}
-.lean .uuid {
+
+.field .shadow.card:hover {
+ opacity: 1;
+ background-color: var(--bg-elevated);
+}
+
+.field .shadow.card a {
+ display: block;
+}
+
+.field .card h3 {
font-size: 18px;
- font-weight: bold;
- font-family: monospace;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin-bottom: 12px;
}
-.lean .fail.name,
-.lean .fail .name { color: #FF1D25; }
-.lean .schedule,
-.lean .notes,
-.lean .retain {
- line-height: 1.1em;
+
+.card,
+.summary {
+ padding: 24px;
+ width: 42%;
+ margin: 2% 0 0 2%;
+ float: left;
}
-.lean .notes {
- width: 40%;
+
+.card:nth-child(2n+1) {
+ clear: both;
+ margin: 2% 2% 2% 0;
}
-.lean .notes .no-data {
- padding: 0px;
- font-size: 100%;
+
+.card > a {
+ color: inherit;
+ text-decoration: none;
}
-.lean td .tag {
- font-size: 8pt;
- font-family: monospace;
- font-weight: bold;
- color: #fff;
- background-color: #aaa;
- border-radius: 4px;
- padding: 3px 5px;
- border: none;
- vertical-align: top;
+
+.card {
+ position: relative;
}
-.lean td .tag.fixed { background-color: darkorchid; }
-.lean td .tag.randomized { background-color: darkblue; }
-.lean tbody tr:nth-child(2n+1) {
- background-color: #F2F2F2;
+.card .type {
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ position: absolute;
+ left: 16px;
+ bottom: 12px;
+ color: var(--text-tertiary);
+ letter-spacing: 0.5px;
}
+.card .details {
+ font-size: 14px;
+ padding: 8px 0;
+ color: var(--text-secondary);
+}
-.choose.target .not-selectable {
- opacity: 0.2;
+.card .details strong {
+ font-weight: 600;
+ color: var(--text-primary);
}
-h2 ul.switcher {
+.card img {
+ width: 24px;
float: right;
+ opacity: 0.8;
}
-h2 ul.switcher li {
- float: right;
- padding: 4px;
+
+.card.fail img {
+ width: 36px;
}
-h2 ul.switcher li img {
- width: 20px;
- opacity: 0.5;
+
+.card.fail h3 {
+ color: var(--error);
}
-h2 ul.switcher li:hover img {
- opacity: 1.0;
+
+.card .notes {
+ font-size: 14px;
+ padding: 1em 0;
+ font-style: italic;
+ line-height: 1.5;
+ color: var(--text-secondary);
}
-.switch-me.card-view .lean,
-.switch-me.lean-view .cards { display: none; }
+.card .notes strong {
+ font-weight: 600;
+ color: var(--text-primary);
+}
-.switch-me.card-view a[href^="switch:card-view"] img { opacity: 0.8; }
-.switch-me.lean-view a[href^="switch:lean-view"] img { opacity: 0.95; }
+.no-data {
+ font-style: italic;
+ text-align: center;
+ opacity: 0.5;
+ font-size: 14px;
+ padding: 3em 0;
+ color: var(--text-tertiary);
+}
-.gutter > h2 { font-size: 28px; font-weight: bold; clear: both; }
-.gutter > h3 { font-size: 22px; font-weight: bold; }
-.gutter > h4 { font-size: 18px; font-weight: bold; }
-.gutter > h2, .gutter > h3, .gutter > h4
-{ line-height: 1.6em; margin-top: 0.6em; }
+.summary h2 {
+ font-size: 18px;
+ font-weight: 600;
+ margin-bottom: 16px;
+}
-.field p {
- margin: 1em 0;
+.summary p {
+ margin: 0.5em 0;
+ color: var(--text-secondary);
}
-.field p a {
- text-decoration: none;
- border: 1px dotted #0071bc;
- border-width: 0 0 1px 0;
- color: #0071bc;
+
+.store .summary {
+ width: 100%;
+ margin: 1em;
+ float: none;
+ font-style: italic;
}
-.field a.breadcrumb,
-.field a.new, .field a.edit, .field a.delete {
- text-decoration: none;
- color: #0071bc;
- font-size: 11pt;
- border-bottom: 1px dotted #0071bc;
+table.lean td.name > .tag,
+.store h2 .tag {
+ background-color: var(--accent-primary);
+ color: #fff;
+ border-radius: 4px;
+ font-size: 11px;
+ font-weight: 600;
+ padding: 4px 8px;
display: inline-block;
+ position: relative;
+ top: -2px;
+ left: 6px;
+ letter-spacing: 0.3px;
}
-.field a.new {
- display: block;
- float: right;
-}
-.field a.edit, .field a.delete {
- margin-left: 1ex;
- font-weight: bold;
-}
-.field a.delete {
- color: #FF6161;
- border-color: #FF6161;
-}
+
+/* ================================================
+ TABLES
+ ================================================ */
.field table {
width: 96%;
- margin: 2% 2% 6% 2%;
+ margin: 2% 2%;
+ background-color: var(--bg-card);
+ border-radius: var(--radius-lg);
+ overflow: hidden;
+ box-shadow: var(--shadow-md);
+ border: 1px solid var(--border-default);
}
+
.field table th,
.field table td {
- padding: 0.75em;
- font-size: 15px;
+ padding: 16px;
+ font-size: 14px;
text-align: left;
+ border-bottom: 1px solid var(--border-muted);
}
+
.field table thead th {
- border-bottom: 2px dotted #ccc;
- font-weight: bold;
+ font-weight: 600;
text-align: left;
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ border-bottom: 1px solid var(--border-default);
+}
+
+.field table tbody tr {
+ transition: background-color 0.2s ease;
}
+
+.field table tbody tr:hover {
+ background-color: var(--bg-tertiary);
+}
+
+.field table tbody tr:last-child td {
+ border-bottom: none;
+}
+
.field table a {
- color: #0071BC;
+ color: var(--accent-primary);
text-decoration: none;
+ transition: color 0.2s ease;
}
-.field table td span.fail { color: #ED1C24; }
-.field table .noted td { font-weight: bold; }
-.field table .note + .noted { border-top: 12px solid #fff; }
+.field table a:hover {
+ color: var(--accent-light);
+}
-.field table .note strong {
- font-weight: bold;
- display: block;
- font-variant: small-caps;
+.field table td span.fail {
+ color: var(--error);
+ font-weight: 600;
}
-.field table .note div {
- white-space: pre-wrap;
- margin: 1%;
- line-height: 1.3em;
+
+.lean img {
+ width: 16px;
+ opacity: 0.8;
+}
+
+.lean .name {
+ font-size: 16px;
+ font-weight: 600;
+ white-space: nowrap;
+}
+
+.lean .name a {
+ text-decoration: none;
+ color: inherit;
}
-.field table .noted td,
-.field table .note td
-{ background-color: rgba(0,113,188,0.125); }
+.lean .uuid {
+ font-size: 14px;
+ font-weight: 600;
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
+ color: var(--text-secondary);
+}
-.field table .noted.fail td,
-.field table .note.fail td
-{ background-color: rgba(255,29,37,0.125); }
+.lean .fail.name,
+.lean .fail .name {
+ color: var(--error);
+}
-.field table .noted.ok td,
-.field table .note.ok td
-{ background-color: rgba(140,198,63,0.125); }
+.lean tbody tr:nth-child(2n+1) {
+ background-color: var(--bg-tertiary);
+}
-.field table tr.task { display: none; }
+table th.sortable {
+ cursor: pointer;
+ user-select: none;
+}
+table th.sortable:hover {
+ color: var(--accent-primary);
+}
-form .band .field {
- clear: both;
- overflow: hidden;
- margin: 1.33em 0;
+table th.sortable.asc ::before,
+table th.sortable.desc ::before {
+ margin-left: 4px;
+ content: "\25b4";
+ display: inline-block;
+ opacity: 0.5;
+ font-size: 10px;
}
-form .ctl { width: 70%; margin: 1em 0 2em 0; }
-form .info { width: 45%; float: right; clear: right; }
-form .info {
- border-radius: 8px;
- background-color: rgba(0, 118, 188, 0.2);
- padding: 16px;
- box-sizing: border-box;
- font-size: 14px;
+table th.sortable.asc ::before {
+ transform: rotate(180deg);
}
-form .info { display: none; }
-form .band.active .info { display: block; }
+
+/* ================================================
+ FORMS
+ ================================================ */
form .ctl {
- margin-bottom: 2em;
+ width: 70%;
+ margin: 2em 0;
}
-form .ctl label {
- font-weight: bold;
- font-size: 18px;
- line-height: 20px;
- display: block;
- width: 50%;
- float: left;
-}
-form .ctl .widget {
+form .ctl label {
+ font-weight: 600;
+ font-size: 15px;
+ line-height: 1.5;
display: block;
- clear: both;
- margin-top: 0.5em;
+ color: var(--text-primary);
+ margin-bottom: 8px;
}
+
form .ctl input,
form .ctl select,
form .ctl textarea {
- font-size: 18px;
+ font-size: 15px;
display: block;
- margin-bottom: 4px;
+ margin-bottom: 8px;
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ padding: 12px;
+ transition: all 0.2s ease;
+ font-family: inherit;
}
-form .ctl select,
-form .ctl input[type=text],
-form .ctl input[type=password] {
- width: 100%;
+
+form .ctl input:focus,
+form .ctl select:focus,
+form .ctl textarea:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
+ background-color: var(--bg-elevated);
}
+
form .ctl input[type=text],
form .ctl input[type=password],
-form .ctl input[type=file] {
- border: 1px solid #ccc;
- border-width: 0 0 1px 0;
-}
-form .ctl input[type=checkbox] {
- float: left;
+form .ctl select {
+ width: 100%;
}
+
form .ctl textarea {
- min-height: 6em;
+ min-height: 120px;
width: 100%;
+ resize: vertical;
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
}
+
form .ctl p {
font-size: 13px;
padding: 4px 0;
font-style: italic;
+ color: var(--text-secondary);
}
+
form .ctl p strong {
- color: #0071BC;
- font-weight: bold;
+ color: var(--accent-primary);
+ font-weight: 600;
}
-form .ctl .help {
-}
form .ctl tt {
- font-family: monospace;
- color: #0071bc;
- font-weight: bold;
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
+ color: var(--accent-primary);
+ font-weight: 600;
font-style: normal;
- padding: 2px 4px;
-}
-form .ctl .if-missing {
- color: darkred;
+ padding: 2px 6px;
+ background-color: var(--bg-tertiary);
+ border-radius: 4px;
font-size: 13px;
- display: none;
}
form .error,
form .ctl span.errors {
- color: crimson;
+ color: var(--error);
font-size: 13px;
}
-form .ctl span.errors {
- width: 60%;
- display: block;
- float: right;
- text-align: right;
-}
-form .error,
-form .errors span[data-error],
-form .ctl span[data-error] {
- display: none;
-}
-.ctl.required label span {
- font-size: 10pt;
- font-weight: normal;
- color: #0071bc;
- vertical-align: top;
+
+form button.go {
+ background-color: var(--accent-primary);
+ border: none;
+ color: white;
+ font-size: 16px;
+ height: 48px;
+ border-radius: var(--radius-md);
+ padding: 0 32px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s ease;
}
-form .subform .ctl {
- margin-left: 1em;
+form button.go:hover {
+ background-color: var(--accent-hover);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md);
}
-form .subform h2 {
- font-size: 18pt;
- font-weight: bold;
- color: #0071bc;
+
+form button.go:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ transform: none;
}
-form button.go {
- background-color: #0071BC;
- border: 1px solid #0071BC;
- color: #fff;
+/* ================================================
+ BUTTONS
+ ================================================ */
- font-size: 16pt;
- height: 36px;
- border-radius: 4px;
- padding: 0 0.6em;
- margin: 0;
- box-sizing: border-box;
- font-weight: bold;
+button {
cursor: pointer;
+ background-color: var(--accent-primary);
+ padding: 12px 24px;
+ border-radius: var(--radius-md);
+ border: none;
+ color: white;
+ font-size: 14px;
+ font-weight: 500;
+ transition: all 0.2s ease;
}
-.e404 {
- max-width: 800px;
-}
-.e404 h2 {
- margin-bottom: 2em;
+button:hover:not(:disabled) {
+ background-color: var(--accent-hover);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md);
}
-.e404 img {
- float: right;
- margin: 0 0 2em 4em;
-}
-.e404 p {
- padding: 0 2em 3em 2em;
- font-size: 16px;
- line-height: 1.4em;
-}
-.e404 p a {
- font-weight: bold;
- color: #0071bc;
-}
-.e404 pre {
- opacity: 0.1;
- white-space: pre;
- font-family: monospace;
- font-size: 16px;
- padding: 0 0 0 2em;
-}
-.e404 pre:hover {
- opacity: 1;
- cursor: i-beam;
-}
-
-.meter svg {
- width: 100%;
- min-width: 540px;
+button:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
}
-.plugin {
- background-color: #0071BC;
- color: #fff;
- border-radius: 7px;
- padding: 10px;
-
- font-size: 70%;
- float: right;
- line-height: 1em;
-}
+/* ================================================
+ TIMELINE
+ ================================================ */
-.side-by-side {
- box-sizing: border-box;
- width: 50%;
- padding: 2%;
- float: left;
-}
-.side-by-side h3 {
- font-size: 22px; font-weight: bold;
- border-bottom: 1px solid #ccc;
- margin: 1em 0;
+.timeline .event {
+ position: relative;
+ border-left: 3px solid var(--border-default);
+ padding-left: 24px;
+ margin-left: 12px;
+ padding-bottom: 32px;
}
-dl {
- overflow: hidden;
-}
-dl dt {
- clear: left;
- float: left;
+.timeline .event::before {
+ content: '';
display: block;
- width: 40%;
- padding: 0 0 0.75em 0;
-}
-dl dd {
- float: left;
- font-weight: bold;
- padding: 0 0 0.75em 0;
-}
-dl dd span.redacted {
- color: crimson;
-}
-dl dd span.not-configured {
- font-style: italic;
- font-weight: normal;
- color: #aaa;
+ width: 12px;
+ height: 12px;
+ background-color: var(--border-default);
+ border: 3px solid var(--bg-primary);
+ border-radius: 50%;
+ position: absolute;
+ top: 0;
+ left: -10.5px;
}
-dl dd em:before { content: "«"; }
-dl dd em:after { content: "»"; }
-pre code {
- display: block;
- background-color: #003d63;
- color: white;
- font: 10pt/16pt Monaco, monospace;
- padding: 1em;
- white-space: pre-wrap;
+.timeline .event.ok {
+ border-left-color: var(--success);
}
-pre code .hi { color: yellow; font-weight: bold; }
-pre code em { color: lightblue; }
-pre code em em { color: #ccc; }
-pre code button {
- float: right;
- color: #fff;
- background-color: #0071BC;
- box-shadow: 2px 2px 5px 1px rgba(0,0,0, 0.3);
- border: none;
- border-radius: 3px;
- font: 12pt/16pt Monaco, monospace;
- text-transform: uppercase;
-
- padding: 4pt 9pt;
- cursor: pointer;
- margin-left: 0.75em;
+.timeline .event.ok::before {
+ background-color: var(--success);
}
-pre code button.restore:hover { background-color: #8CC63F; }
-pre code button.annotate:hover { background-color: purple; }
-pre code button.close:hover { background-color: red; }
-pre code div {
- white-space: normal;
+.timeline .event.failed,
+.timeline .event.canceled {
+ border-left-color: var(--error);
}
-pre code div form {
- clear: both;
- float: right;
- width: 40%;
- padding-top: 1ex;
-}
-pre code div form.annotate { display: none; }
-
-pre code label,
-pre code input,
-pre code select,
-pre code textarea {
- width: 100%;
- display: block;
- box-sizing: border-box;
- font: inherit;
- color: inherit;
- background-color: inherit;
-}
-pre code input[type=radio],
-pre code input[type=checkbox] {
- display: inline-block;
- width: auto;
-}
-pre code input + label {
- padding-left: 1ex;
- display: inline-block;
- width: auto;
- cursor: pointer;
-}
-pre code ul {
- padding-left: 1em;
-}
-pre code textarea {
- border: 1px solid white;
- height: 140px;
- margin-bottom: 1ex;
-}
-pre code form ul {
- margin: 1em 0;
+.timeline .event.failed::before,
+.timeline .event.canceled::before {
+ background-color: var(--error);
}
-pre.task-canceled code,
-pre.task-failed code { background-color: #5e0000; }
-pre.task-canceled code em,
-pre.task-failed code em { color: #eee; }
-pre.task-canceled code em em,
-pre.task-failed code em em { color: salmon; }
-pre.task-canceled code button,
-pre.task-failed code button { background-color: #222; }
-
-pre.task-canceled.override code,
-pre.task-failed.override code { background-color: #333; }
-
-
-.timeline {
- /*
- border-left: 3px solid #777;
- padding-left: 6px;
- margin-left: 6px;
- */
+.timeline .event.running {
+ border-left-color: var(--info);
}
-.timeline .event {
- position: relative;
- border-left: 3px solid #777;
- padding-left: 10px;
- margin-left: 6px;
- padding-bottom: 24px;
-}
-.timeline .event::before {
- content: '';
- display: block;
- width: 12px;
- height: 12px;
- background-color: #777;
- border: 3px solid #fff;
- border-radius: 12px;
- position: absolute;
- top: 0px;
- left: -10.5px;
+.timeline .event.running::before {
+ background-color: var(--info);
}
-.timeline .event.ok { border-left-color: #8cc63f; }
-.timeline .event.ok::before { background-color: #8cc63f; }
-.timeline .event.canceled,
-.timeline .event.failed { border-left-color: #ff1d25; }
-.timeline .event.canceled::before,
-.timeline .event.failed::before { background-color: #ff1d25; }
-.timeline .event.running { border-left-color: #0071bc; }
-.timeline .event.handled::before { background-color: #0071bc; }
-.timeline .event.running { border-left-color: #777777; }
-.timeline .event.handled::before { background-color: #777777; }
-
.timeline .event .date {
display: inline-block;
- font-size: 14pt;
+ font-size: 14px;
+ color: var(--text-secondary);
+ margin-bottom: 4px;
}
+
.timeline .event .tag {
- background-color: #ccc;
+ background-color: var(--bg-tertiary);
border-radius: 4px;
- font-size: 8pt;
- font-weight: bold;
+ font-size: 11px;
+ font-weight: 600;
padding: 4px 8px;
display: inline-block;
-
position: relative;
- top: -3px;
- left: 3px;
+ top: -2px;
+ left: 6px;
+ color: var(--text-secondary);
}
-.timeline .event.canceled .tag,
-.timeline .event.failed .tag { display: none; }
+
.timeline .event.backup .tag {
color: #fff;
- background-color: #8CC63F;
+ background-color: var(--success);
}
+
.timeline .event.restore .tag {
color: #fff;
- background-color: darkviolet;
+ background-color: #8b5cf6;
}
+
.timeline .event .desc {
- font-size: 18pt;
- line-height: 24pt;
- font-weight: bold;
+ font-size: 18px;
+ line-height: 1.5;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin: 8px 0;
}
-.timeline .event.canceled .desc,
-.timeline .event.failed .desc { color: #ff1d25; }
-.timeline .event.canceled .desc::after { content: " — CANCELED"; }
-.timeline .event.failed .desc::after { content: " — FAILED"; }
-.timeline .event.handled .desc { color: inherit; }
-.timeline .event.handled .desc::after { content: " — handled"; }
-.timeline .event .meta {
+.timeline .event.failed .desc,
+.timeline .event.canceled .desc {
+ color: var(--error);
+}
+
+.timeline .event.canceled .desc::after {
+ content: " — CANCELED";
+}
+
+.timeline .event.failed .desc::after {
+ content: " — FAILED";
}
.timeline .event .note {
display: block;
max-width: 40em;
margin: 1em 0;
- background-color: #fffac7;
+ background-color: var(--bg-tertiary);
padding: 1em;
- border: 1px dashed #ccc;
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ color: var(--text-secondary);
}
+
.timeline .event .note a {
text-decoration: none;
- border-bottom: 1px dashed #ccc;
- color: blue;
+ border-bottom: 1px dashed var(--accent-primary);
+ color: var(--accent-primary);
}
+
.timeline .event .note strong {
- font-weight: bold;
+ font-weight: 600;
text-transform: uppercase;
+ color: var(--text-primary);
}
-.timeline .event .task { display: none; }
-
.timeline .event .expand {
visibility: hidden;
display: block;
- margin-top: 4px;
- font-size: 10pt;
+ margin-top: 8px;
+ font-size: 13px;
}
+
.timeline .event:hover .expand {
visibility: visible;
}
+
.timeline .event .expand a {
text-decoration: none;
- color: #0071bc;
-}
-
-.paginate .loading {
- font-style: italic;
- text-align: center;
- opacity: 0.5;
- font-size: 120%;
- padding: 2.5em 0 4em 0;
+ color: var(--accent-primary);
}
+/* ================================================
+ MODALS
+ ================================================ */
#modal.modal-wash {
position: fixed;
- top: 0px;
- left: 0px;
+ top: 0;
+ left: 0;
width: 100vw;
- height: 100vw;
- background-color: rgba(255,255,255,0.85);
+ height: 100vh;
+ background-color: rgba(0, 0, 0, 0.7);
+ backdrop-filter: blur(4px);
z-index: 140;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
+
#modal > .confirm {
box-sizing: border-box;
- box-shadow: 0 0 12px #333;
- width: 70vw;
- min-height: 30vh;
- max-height: 70vh;
- margin: 15vh 15vw;
- padding: 0 0 20px 0;
- overflow: scroll;
-
- border-radius: 0.6em;
- background-color: #fff;
- color: #000;
+ box-shadow: var(--shadow-xl);
+ width: 500px;
+ max-width: 90vw;
+ max-height: 80vh;
+ padding: 0;
+ overflow: hidden;
+ border-radius: var(--radius-lg);
+ background-color: var(--bg-card);
+ color: var(--text-primary);
+ border: 1px solid var(--border-default);
}
+
#modal > .confirm h2 {
- font-size: 150%;
- background-color: firebrick;
- color: #fff;
- padding: 0.5em;
- font-weight: bold;
+ font-size: 20px;
+ background-color: var(--error);
+ color: white;
+ padding: 20px;
+ font-weight: 600;
text-align: center;
+ margin: 0;
}
+
#modal > .confirm p {
- margin: 1em auto;
- font-size: 120%;
- line-height: 1.2em;
- max-width: 680px;
+ margin: 20px;
+ font-size: 15px;
+ line-height: 1.6;
}
+
#modal > .confirm p em {
- font-weight: bold;
- color: #0071bc;
-}
-#modal > .confirm p.q {
- font-size: 160%;
- margin: 1em auto;
- width: 60%;
- text-align: center;
+ font-weight: 600;
+ color: var(--accent-primary);
}
+
#modal .confirm .a {
max-width: 680px;
text-align: center;
margin: 1em auto;
+ padding: 20px;
}
+
#modal > .confirm button {
- display: inline-block;
- border: none;
- border-radius: 2px;
- font-size: 140%;
- padding: 8px 16px;
- margin: 0.33em;
- cursor: pointer;
-}
-#modal > .confirm button {
- border-radius: 0.33em;
- border: 2px solid #0071bc;
+ border: 2px solid var(--accent-primary);
background-color: transparent;
- color: #0071bc;
- font-size: 120%;
- padding: 0.5em 2em;
+ color: var(--accent-primary);
+ font-size: 14px;
+ padding: 12px 24px;
+ margin: 8px;
}
+
#modal > .confirm button.safe {
- background-color: #0071bc;
- color: #fff;
+ background-color: var(--accent-primary);
+ color: white;
}
-.wizard2 h1 {
- margin: 2em 0 0 0;
- font-size: 28pt;
- font-weight: bold;
-}
-.wizard2 .intro p {
- width: 70%;
- margin: 1em;
- line-height: 1.2em;
-}
-.wizard2 h2 {
- font-size: 22pt;
- font-weight: bold;
- margin: 3em 0 0.7em 0;
-}
-.wizard2 h3 {
- font-size: 18pt;
- font-weight: bold;
- margin: 4em 0 1.5em 0;
-}
-.wizard2 h2:first-child {
- margin-top: 1em;
-}
-.wizard2 h2 span {
- font-size: 14pt;
- color: #0071bc;
+/* ================================================
+ CODE BLOCKS
+ ================================================ */
+
+pre code {
display: block;
- margin: 1em 0 0.33em 0;
-}
-.wizard2 .no-further {
- margin: 1em;
- padding: 1em;
- background-color: darkred;
- color: white;
- border-radius: 0.5em;
- width: 70%;
-}
-.wizard2 .no-further a {
- font-weight: bold;
- border-bottom: 1px dotted #fff;
- color: inherit;
- text-decoration: none;
-}
-.wizard2 .band {
- clear: both;
- padding: 0.5em 0;
- overflow: hidden;
-}
-.wizard2 .band.hover:hover {
- background-color: #f2f2f2;
-}
-.wizard2 .band.hover input {
- background-color: transparent;
-}
-.wizard2 .errors span {
- display: none;
- padding: 8px 2px;
- font-size: 13px;
- color: crimson;
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ font: 12px/1.6 'Monaco', 'Menlo', 'Consolas', monospace;
+ padding: 20px;
+ border-radius: var(--radius-md);
+ white-space: pre-wrap;
+ overflow-x: auto;
+ border: 1px solid var(--border-default);
}
-.wizard2 .help {
- font-size: 10pt;
- line-height: 1.2em;
- color: #0071bc88;
- font-style: italic;
+
+pre code .hi {
+ color: var(--warning);
+ font-weight: 600;
}
-.wizard2 .help .example {
- color: orange;
- font-weight: bold;
+
+pre code em {
+ color: var(--accent-light);
}
-.wizard2 .side-help {
- padding: 1em;
- margin: 1em;
- position: relative;
- background-color: #0071bc22;
+
+pre code em em {
+ color: var(--text-secondary);
}
-.wizard2 .lean.selectable tbody tr:not(.not-selectable):hover,
-.wizard2 .lean.selectable.selected tbody tr.selected {
- cursor: pointer;
- padding: 0px;
- background-color: #000;
+pre code button {
+ float: right;
color: #fff;
- opacity: 1.0;
+ background-color: var(--accent-primary);
+ box-shadow: var(--shadow-md);
+ border: none;
+ border-radius: var(--radius-sm);
+ font: 12px/1 'Monaco', 'Menlo', 'Consolas', monospace;
+ text-transform: uppercase;
+ padding: 8px 12px;
+ cursor: pointer;
+ margin-left: 12px;
}
-.wizard2 .lean.selectable.selected tbody tr {
- opacity: 0.3;
+
+pre code button.restore:hover {
+ background-color: var(--success);
}
-.wizard2 .lean.selectable tbody tr:not(.not-selectable):hover td.name,
-.wizard2 .lean.selectable.selected tbody tr td.name {
- color: inherit;
+
+pre code button.annotate:hover {
+ background-color: #8b5cf6;
}
-.wizard2 .x3 label,
-.wizard2 .x2 label {
- font-weight: bold;
- text-align: right;
- display: block;
- padding-right: 16px;
- padding-top: 10px;
+
+pre code button.close:hover {
+ background-color: var(--error);
}
-.wizard2 label span {
- display: block;
- text-align: right;
- font-size: 11pt;
- font-size: 9pt;
- font-weight: normal;
- color: #aaa;
- line-height: 1.4em;
+
+pre.task-canceled code,
+pre.task-failed code {
+ background-color: rgba(239, 68, 68, 0.1);
+ border-color: var(--error);
}
-.wizard2 .errors {
- display: block;
+/* ================================================
+ NOTICES
+ ================================================ */
+
+.notice {
+ background-color: rgba(59, 130, 246, 0.1);
+ padding: 16px;
+ border-radius: var(--radius-md);
+ font-size: 14px;
+ border: 1px solid rgba(59, 130, 246, 0.2);
+ margin: 16px 0;
+ line-height: 1.6;
}
-.wizard2 .scheduling .optgroup li {
- border-radius: 0px;
- margin: 4px 0px;
+.notice strong,
+h2 strong {
+ font-weight: 600;
+ color: var(--accent-primary);
}
-.wizard2 .scheduling .optgroup li:first-child { border-radius: 4px 0 0 4px; }
-.wizard2 .scheduling .optgroup li:last-child { border-radius: 0 4px 4px 0; }
-.wizard2 .scheduling .optgroup li+li {
- border-left: 0;
+
+.notice.failure {
+ background-color: rgba(239, 68, 68, 0.1);
+ border-color: rgba(239, 68, 68, 0.2);
+ color: var(--error);
}
-.wizard2 [data-step] [data-mode] { display: none; }
-.wizard2 [data-step][data-mode="choose"] [data-mode="choose"],
-.wizard2 [data-step][data-mode="create"] [data-mode="choose"],
-.wizard2 [data-step][data-mode="create"] [data-mode="create"] { display: block; }
-.wizard2 [data-step][data-mode="create"] [data-mode="choose"] .buttons { display: none; }
+/* ================================================
+ LOCKED STATE — compact warning banner
+ ================================================ */
-.wizard2 .progress {
- position: relative;
+.locked {
+ display: none;
+ margin: 16px 24px 0;
+ padding: 10px 16px;
+ background-color: rgba(239, 68, 68, 0.08);
+ border: 1px solid rgba(239, 68, 68, 0.25);
+ border-left: 3px solid var(--error);
+ border-radius: var(--radius-md);
+ color: var(--text-primary);
+ align-items: center;
+ gap: 16px;
+ flex-wrap: wrap;
}
-.wizard2 .progress .line {
- height: 4px;
- margin: 0 auto;
- top: 23px;
- position: absolute;
- left: 10%;
- z-index: -1;
+
+/* jQuery fadeIn sets display:block — override to flex */
+#lock-state[style*="display: block"],
+#lock-state[style*="display:block"] {
+ display: flex !important;
}
-.wizard2 .progress .back.line {
- background-color: #ccc;
+
+.locked h1 {
+ font-size: 13px;
+ font-weight: 700;
+ color: var(--error);
+ white-space: nowrap;
+ text-transform: uppercase;
+ letter-spacing: 0.3px;
}
-.wizard2 .progress .front.line {
- background-color: #0071bc;
- width: 0%;
+
+.locked > p {
+ font-size: 13px;
+ color: var(--text-secondary);
+ margin: 0;
+ line-height: 1.4;
}
-.wizard2 .progress ul {
+
+.locked form {
display: flex;
+ align-items: center;
+ gap: 0;
+ margin-left: auto;
}
-.wizard2 .progress li {
- color: inherit;
- text-decoration: none;
- display: inline-block;
- font-size: 9pt;
- text-align: center;
- padding: 0 1em;
+
+.locked form .errors {
+ display: none;
}
-.wizard2 .progress strong {
- font-weight: bold;
- font-size: 12pt;
- display: block;
- margin: 0.7em;
+
+.locked form .error {
+ display: none;
}
-.wizard2 .progress i {
- text-decoration: none;
- background-color: #ccc;
- border-radius: 100%;
- padding: 4px;
- font-size: 15pt;
- width: 32px;
- height: 32px;
- display: block;
- margin: 0 auto;
- color: #fff;
- font-weight: bold;
- line-height: 32px;
- text-align: center;
- border: 4px solid #fff;
+
+.locked form input[type=password] {
+ font-size: 13px;
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ border: 1px solid var(--border-default);
+ border-right: none;
+ border-radius: var(--radius-md) 0 0 var(--radius-md);
+ padding: 7px 12px;
+ width: 18em;
+ outline: none;
+ transition: border-color 0.2s ease;
}
-.wizard2 .progress li.completed i {
- background-color: #0071bc;
+
+.locked form input[type=password]:focus {
+ border-color: var(--error);
}
-.wizard2 .progress li.current i {
- background-color: #8cc63f;
-}
-
-.wizard2.steps4 .progress .line { width: 75%; left: 12.5%; }
-.wizard2.steps4 .progress .front.line { width: 0%; }
-.wizard2.steps4 .progress li { width: 25%; }
-.wizard2.steps4[data-on-step="2"] .progress .front.line { width: 25%; }
-.wizard2.steps4[data-on-step="3"] .progress .front.line { width: 50%; }
-.wizard2.steps4[data-on-step="4"] .progress .front.line { width: 75%; }
-
-.wizard2.steps5 .progress .line { width: 80%; left: 10%; }
-.wizard2.steps5 .progress .front.line { width: 0%; }
-.wizard2.steps5 .progress li { width: 20%; }
-.wizard2.steps5[data-on-step="2"] .progress .front.line { width: 20%; }
-.wizard2.steps5[data-on-step="3"] .progress .front.line { width: 40%; }
-.wizard2.steps5[data-on-step="4"] .progress .front.line { width: 60%; }
-.wizard2.steps5[data-on-step="5"] .progress .front.line { width: 80%; }
-
-.wizard2 .buttons button[rel=prev] { float: left; }
-.wizard2 .buttons button[rel=next],
-.wizard2 .buttons button.final { float: right; }
-
-.wizard2 .buttons .wizard-cannot-continue {
- font-size: 12pt;
- line-height: 1.2em;
- background-color: darkred;
+
+.locked form button[type=submit] {
+ font-size: 13px;
+ background-color: var(--error);
color: #fff;
- border-radius: 0.6em;
- padding: 1em;
-}
-.wizard2 button { font-size: 12pt; }
-.wizard2 button span { color: yellow; }
-.wizard2 button[rel=prev] {
- background: none;
- box-shadow: none;
- color: #333;
-}
-.wizard2 button[rel=prev] span {
- color: #0071bc;
-}
-.wizard2 button.final {
- font-size: 140%;
+ border: 1px solid var(--error);
+ border-radius: 0 var(--radius-md) var(--radius-md) 0;
+ padding: 7px 14px;
+ cursor: pointer;
+ transition: background-color 0.15s ease;
}
-.wizard2 button.final.submitting {
- opacity: 0.5;
+
+.locked form button[type=submit]:hover {
+ background-color: #dc2626;
}
-.wizard2 button.final.submitting :after {
- content: "...";
+
+/* ================================================
+ THEME TOGGLE BUTTON (top-bar inline)
+ ================================================ */
+
+.theme-toggle {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ background: transparent;
+ border: 1px solid var(--border-default);
+ color: var(--text-secondary);
+ font-size: 13px;
+ cursor: pointer;
+ transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
+ flex-shrink: 0;
+ padding: 0;
}
-.wizard2 button.final:disabled {
- opacity: 0.3;
- cursor: not-allowed;
+
+.theme-toggle:hover {
+ background-color: var(--bg-elevated);
+ color: var(--text-primary);
+ border-color: var(--accent-primary);
+ transform: none;
+ box-shadow: none;
}
+/* Dark mode (default): show sun → clicking switches to light */
+.theme-icon-light { display: inline; }
+.theme-icon-dark { display: none; }
-.wizard2 input::placeholder {
- color: #888;
- font-size: 80%;
- font-style: italic;
+/* Light mode: show moon → clicking switches to dark */
+[data-theme="light"] .theme-icon-light { display: none; }
+[data-theme="light"] .theme-icon-dark { display: inline; }
+
+/* ================================================
+ MISC UTILITIES
+ ================================================ */
+
+.choose.target .not-selectable {
+ opacity: 0.3;
}
-.wizard2 .selected-elsewhere,
-.wizard2 input[type=password],
-.wizard2 input[type=text] {
+
+redacted {
background-color: transparent;
- border: 2px solid #0071bc;
- border-width: 0 0 2px 0;
- font-size: 18pt;
+ color: inherit;
+ filter: blur(10px);
+ font-weight: 900;
}
-.wizard2 .selected-elsewhere {
- border: 0;
- margin: 0;
- margin-top: 8px;
+
+redacted:hover {
+ filter: none;
+ font-weight: inherit;
}
-.wizard2 .selected-elsewhere span.tag {
- display: inline-block;
- background-color: #8cc63f;
- color: #fff;
- font-size: 8pt;
- line-height: 6pt;
- font-weight: bold;
- padding: 4pt 6pt 3pt 6pt;
- position: relative;
- top: -10pt;
- border-radius: 2pt;
+.denied {
+ font-style: italic;
+ color: var(--text-tertiary);
+ font-size: 13px;
+ padding: 0em 3em;
+ display: block;
}
-.wizard2 .selected-elsewhere a {
- font-size: 11pt;
- color: #0071bc;
+
+a.load-more {
text-decoration: none;
- border-bottom: 1px dotted #0071bc;
-}
-.wizard2 input[type=password][!size],
-.wizard2 input[type=text][!size] {
- width: 60%;
-}
-.wizard2 textarea {
- height: 7em;
- border: 1px solid #0071bc;
- width: 90%;
- font-family: sans-serif;
- padding: 0.7em;
- line-height: 1.2em;
-}
-.wizard2 select {
- font-size: 12pt;
- padding: 4px;
- margin: 4px 0;
-}
-.wizard2 .subform {
- display: none;
-}
-.wizard2 .subform > div {
- margin-bottom: 1em;
-}
- /* The switch - the box around the slider */
-.wizard2 .switch {
- position: relative;
- display: inline-block;
- width: 40px;
- height: 24px;
- margin-top: 6px;
+ color: var(--text-secondary);
+ display: block;
+ border: 1px solid var(--border-default);
+ padding: 2em;
+ margin: 1em auto;
+ width: 10em;
+ text-align: center;
+ border-radius: var(--radius-lg);
+ transition: all 0.2s ease;
}
-/* Hide default HTML checkbox */
-.wizard2 .switch input {
- opacity: 0; width: 0; height: 0;
+a.load-more:hover {
+ border-color: var(--accent-primary);
+ color: var(--accent-primary);
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-md);
}
-/* The slider */
-.wizard2 .slider {
- position: absolute;
- cursor: pointer;
- top: 0; left: 0;
- right: 0; bottom: 0;
- background-color: #ccc;
- -webkit-transition: .4s;
- transition: .4s;
-}
+/* ================================================
+ RESPONSIVE
+ ================================================ */
-.wizard2 .slider:before {
- position: absolute;
- content: "";
- left: 4px; bottom: 4px;
- height: 16px; width: 16px;
- background-color: white;
- -webkit-transition: .4s;
- transition: .4s;
-}
+@media (max-width: 768px) {
+ .story-sidebar {
+ width: 100%;
+ height: auto;
+ position: relative;
+ }
-.wizard2 input:checked + .slider { background-color: #0071bc; }
-.wizard2 input:focus + .slider { box-shadow: 0 0 1px #0071bc; }
-.wizard2 input:checked + .slider:before {
- -webkit-transform: translateX(16px);
- -ms-transform: translateX(16px);
- transform: translateX(16px);
-}
+ .pane {
+ width: 100%;
+ margin-left: 0;
+ }
-/* Rounded sliders */
-.wizard2 .slider.round {
- border-radius: 34px;
-}
+ .nav.sticky {
+ width: 100%;
+ }
-.wizard2 .slider.round:before {
- border-radius: 50%;
-}
+ .card {
+ width: 100%;
+ margin: 16px 0;
+ float: none;
+ }
-.wizard2 .smudge {
- position: relative;
- display: inline-block;
+ #login .oauth2,
+ #login .local {
+ width: 100%;
+ padding: 0;
+ border: none;
+ border-top: 1px solid var(--border-default);
+ padding-top: 20px;
+ }
+
+ #login .local {
+ margin-top: 20px;
+ }
+
+ .frontdoor h1 {
+ font-size: 32px;
+ }
+
+ form .ctl {
+ width: 100%;
+ }
+
+ /* theme-toggle is inline in top-bar; no responsive overrides needed */
}
-.wizard2 .smudge input {
- padding-right: 1.4em;
+
+/* ================================================
+ FOCUS STATES (Accessibility)
+ ================================================ */
+
+*:focus-visible {
+ outline: 2px solid var(--accent-primary);
+ outline-offset: 2px;
}
-.wizard2 .smudge > span {
- position: absolute;
- right: 0;
- height: 33px;
- line-height: 33px;
- font-size: 7pt;
- color: #999;
- text-transform: uppercase;
- cursor: pointer;
- font-family: monospace;
+
+/* ================================================
+ ANIMATIONS
+ ================================================ */
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
-.wizard2 button {
- cursor: pointer;
- background-color: #0071bc;
- padding: 0.7em 1.6em;
- border-radius: 8px;
- border: none;
- color: white;
- font-size: 16pt;
- font-weight: bold;
- margin: 1em 1em 1em 0;
- box-shadow: 4px 4px 5px rgba(0,0,0,0.25)
+.fade-in {
+ animation: fadeIn 0.3s ease-out;
}
-.wizard2 .summary-section {
- padding: 1em;
- background-color: #0071bc22;
- margin-bottom: 2em;
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
}
-.flyout {
- position: fixed;
- top: 38px;
- right: 8px;
- z-index: 110;
+.loading-spinner {
+ animation: spin 1s linear infinite;
+}
- color: #000;
- background-color: #F2F2F2;
- min-width: 200px;
- padding: 0px;
- box-shadow: 0px 4px 5px rgba(0,0,0,0.25);
+/* ================================================
+ WIZARD — Progress Bar
+ ================================================ */
- display: none;
+.wizard2 {
+ padding: 2rem 0;
}
-.flyout::before {
- content: "";
- border: 6px solid transparent;
- border-bottom-color: transparent;
- border-bottom-color: #f2f2f2;
- position: absolute;
- top: -12px;
- right: 8px;
-}
-.flyout .menu {
- padding: 8px 0;
+
+.wizard2 .progress {
+ position: relative;
+ margin: 0 0 2.5rem;
+ padding: 0 1rem;
}
-.flyout .menu .header,
-.flyout .menu .dropdown {
- padding: 4px 8px;
- display: block;
+
+.wizard2 .progress ul {
+ display: flex;
+ justify-content: space-between;
+ position: relative;
+ z-index: 1;
+ padding: 0;
+ margin: 0;
}
-.flyout .menu .header {
- font-weight: bold;
+
+.wizard2 .progress li {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ flex: 1;
+ text-align: center;
+ padding: 0 0.25rem;
+ color: var(--text-tertiary);
+ font-size: 11px;
+ line-height: 1.4;
+ transition: color 0.3s ease;
}
-.flyout .menu .header span {
- font-size: 80%;
- font-weight: normal;
- display: block;
+
+.wizard2 .progress li i {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ background-color: var(--bg-secondary);
+ border: 2px solid var(--border-default);
+ color: var(--text-tertiary);
+ font-size: 13px;
+ font-weight: 700;
+ font-style: normal;
+ margin-bottom: 8px;
+ flex-shrink: 0;
+ transition: all 0.3s ease;
}
-.flyout .menu .divider {
+
+.wizard2 .progress li strong {
display: block;
- margin: 8px 0;
- height: 1px;
- background-color: #ccc;
-}
-.flyout .menu .dropdown:hover {
- background-color: #0071bc;
- color: #fff !important;
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--text-tertiary);
+ margin-bottom: 2px;
+ white-space: nowrap;
+ transition: color 0.3s ease;
}
-.flyout .menu .dropdown.odd {
- font-style: italic;
- font-size: 95%;
+
+.wizard2 .progress li.current i {
+ background-color: var(--accent-primary);
+ border-color: var(--accent-primary);
+ color: #fff;
+ box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2);
}
-.flyout .menu .dropdown.current-tenant {
+
+.wizard2 .progress li.current strong {
+ color: var(--accent-primary);
}
-.flyout .menu .dropdown.current-tenant::after {
- content: " (current)";
+
+.wizard2 .progress li.current {
+ color: var(--text-secondary);
}
-#overlay {
- background-color: #e6e6e6;
- width: 40vw;
- position: absolute;
- top: 30vh;
- left: 30vw;
- border-radius: 8px;
- box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
-}
-#overlay .header {
- border-radius: 8px 8px 0 0;
- background-color: #0071bc;
+.wizard2 .progress li.completed i {
+ background-color: var(--success);
+ border-color: var(--success);
color: #fff;
- padding: 16px 16px 12px 16px;
- border-bottom: 1px solid #666;
-}
-#overlay .frame {
- overflow: auto;
- height: 40vh;
- padding: 16px;
}
-
-.init-shield,
-.unlock-shield {
- display: block;
- margin: 4em;
+.wizard2 .progress li.completed strong {
+ color: var(--success);
}
-.init-shield label,
-.unlock-shield label {
- display: block;
- font-size: 16pt;
- font-weight: bold;
- margin: 16pt 0 4pt 0;
-}
-.init-shield input,
-.unlock-shield input {
- font-size: 18pt;
- width: 80%;
- border-radius: 4px 0 0 4px;
- border: 1px solid #ccc;
- height: 36px;
- margin: 0;
- padding: 0 6pt;
- box-sizing: border-box;
+
+.wizard2 .progress li.completed {
+ color: var(--text-secondary);
}
-.init-shield button,
-.unlock-shield button {
- font-size: 16pt;
- height: 36px;
- border-radius: 4px;
- padding: 0 0.6em;
- margin: 0;
- box-sizing: border-box;
- font-weight: bold;
- cursor: pointer;
+
+/* Connecting track lines behind the circles */
+.wizard2 .progress .back.line,
+.wizard2 .progress .front.line {
+ position: absolute;
+ top: 17px;
+ left: calc(50% / var(--steps, 5) + 1rem);
+ right: calc(50% / var(--steps, 5) + 1rem);
+ height: 2px;
+ z-index: 0;
}
-.unlock-shield input {
- font-size: 18px;
- margin-bottom: 4px;
+.wizard2 .progress .back.line {
+ background-color: var(--border-default);
}
-#unlock-shield .error,
-#unlock-shield .errors {
- color: yellow;
- padding-bottom: .25em;
+.wizard2 .progress .front.line {
+ display: none; /* progress fill handled via step classes */
}
-.unlock-shield button {
- background-color: #0071BC;
- border: 1px solid #0071BC;
- color: #fff;
+/* ================================================
+ WIZARD — Step Visibility & Mode Panels
+ ================================================ */
- border-radius: 0 4px 4px 0;
+.wizard2 [data-step] {
+ display: none;
+}
- display: inline-block;
- position: relative;
- top: -1px;
+/* data-mode panels (choose existing vs. create new) */
+[data-step] > [data-mode] {
+ display: none;
}
-.init-shield button {
+[data-step][data-mode="choose"] > [data-mode="choose"],
+[data-step][data-mode="create"] > [data-mode="create"] {
display: block;
- margin: 12pt 0 8pt 0;
- background-color: #ba1f1f;
- border: 1px solid #a31d1d;
- color: #fff;
}
-.form-group {
- width: 440px;
- max-width: 100%;
- margin: 7px 5px 7px 0;
+/* Wizard step headings */
+.wizard2 h2 {
+ font-size: 22px;
+ font-weight: 700;
+ color: var(--text-primary);
+ margin: 0 0 1.5rem;
+ padding-bottom: 1rem;
+ border-bottom: 1px solid var(--border-default);
+ line-height: 1.3;
}
-.form-group button {
- color: #fff;
- background-color: #0071BC;
- box-shadow: 2px 2px 5px 1px rgba(0,0,0, 0.3);
- border: none;
- border-radius: 3px;
- font: 12pt/16pt Monaco, monospace;
+.wizard2 h2 > span {
+ display: block;
+ font-size: 11px;
+ font-weight: 500;
+ color: var(--text-tertiary);
text-transform: uppercase;
- padding: 5pt 10pt;
- cursor: pointer;
+ letter-spacing: 0.6px;
+ margin-bottom: 4px;
}
-.form-group dt {
- width: 100%;
- padding: 0;
+/* ================================================
+ WIZARD — Form Fields
+ ================================================ */
+
+/* Form rows always carry data-field attribute; scope block layout to avoid
+ colliding with #main which also carries the .field class */
+.field:not(#main) {
+ overflow: hidden;
+ padding: 1rem 0;
+ border-bottom: 1px solid var(--border-muted);
}
-.form-control {
- width: 400px;
- min-height: 20px;
- padding: 6px 8px;
- font-size: 14px;
- border: 1px solid #d1d5da;
- border-radius: 3px;
- box-shadow: inset 0 1px 2px rgba(27,31,35,0.075);
+.field:not(#main):last-child {
+ border-bottom: none;
}
-#admin-home ul li {
- margin: 2em 0 1em 2em;
- width: 60%;
+.field:not(#main) .x3 {
+ padding-top: 0.4rem;
+ padding-right: 1.5rem;
}
-#admin-home ul a {
+
+.field:not(#main) .x3 label {
display: block;
- text-decoration: none;
- font-weight: bold;
- font-size: 16pt;
- margin: 0 0 0.5em 0;
- color: #0071BC;
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--text-primary);
+ line-height: 1.4;
}
-#admin-home ul p {
- font-size: 11pt;
- color: #333;
- margin-bottom: 3em;
+
+.field:not(#main) .x3 label > span {
+ display: block;
+ font-weight: 400;
+ font-size: 11px;
+ color: var(--text-tertiary);
+ margin-top: 2px;
}
+/* Required field asterisk */
+.field:not(#main).required > .x3 label::after {
+ content: ' *';
+ color: var(--error);
+ font-weight: 700;
+}
-.github-auth-overlay-register,
-.github-auth-overlay-app {
- margin: 2em auto;
+/* All form inputs inside wizard/form field rows */
+.field:not(#main) input[type="text"],
+.field:not(#main) input[type="password"],
+.field:not(#main) select,
+.field:not(#main) textarea {
+ width: 100%;
+ font-size: 14px;
+ font-family: inherit;
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-md);
+ padding: 10px 14px;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
display: block;
+ margin-bottom: 4px;
+}
- position: relative;
- border: 1px solid #ccc;
+.field:not(#main) input[type="text"]:focus,
+.field:not(#main) input[type="password"]:focus,
+.field:not(#main) select:focus,
+.field:not(#main) textarea:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
+ background-color: var(--bg-elevated);
+}
- border: 1px solid #ccc;
- box-shadow: 2px 2px 5px 1px rgba(0,0,0, 0.3);
+.field:not(#main) textarea {
+ min-height: 90px;
+ resize: vertical;
+ line-height: 1.5;
}
-.github-auth-overlay-register {
- width: 600px; height: 600px;
- background: transparent url(/i/auth/github1.png) no-repeat 0 0 scroll;
+
+/* Small inline inputs (numeric / time) */
+.field:not(#main) input.num {
+ width: 4.5em;
+ display: inline-block;
+ text-align: center;
+ margin-bottom: 0;
}
-.github-auth-overlay-register > * {
- display: block;
- position: absolute;
- box-sizing: border-box;
- padding: 10px;
- width: 466px; height: 35px;
- left: 19px;
+.field:not(#main) input.time {
+ width: 6em;
+ display: inline-block;
+ margin-bottom: 0;
+}
- line-height: 21px;
- font-size: 18px;
- color: blue;
- font-weight: bold;
+/* Error / validation state */
+.field:not(#main) .errors {
+ display: block;
+ min-height: 1em;
}
-.github-auth-overlay-register .appname { top: 106px; font-size: 21px; }
-.github-auth-overlay-register .homepage { top: 211px; }
-.github-auth-overlay-register .callback { top: 438px; }
-.github-auth-overlay-app {
- width: 600px; height: 340px;
- background: transparent url(/i/auth/github2.png) no-repeat 0 0 scroll;
+.field:not(#main) .errors [data-error] {
+ display: none;
+ color: var(--error);
+ font-size: 12px;
+ margin-top: 4px;
}
-.github-auth-overlay-app > * {
- display: block;
- position: absolute;
- box-sizing: border-box;
- background: rgba(255, 255, 0, 0.5);
- height: 20px;
- left: 5px;
+.field:not(#main).error .errors [data-error="missing"],
+.field:not(#main).invalid .errors [data-error="invalid"] {
+ display: block;
}
-.github-auth-overlay-app .client-id { top: 215px; width: 141px; }
-.github-auth-overlay-app .client-secret { top: 256px; width: 273px; }
-table.tenant-members tbody td:nth-child(1) { width: 12px; padding: 0; }
-table.tenant-members tbody td:nth-child(2) { width: 30%; }
-table.tenant-members tbody td:nth-child(3) { width: 30%; }
-table.tenant-members tbody td:nth-child(4) { width: 40%; }
+.field:not(#main).error input,
+.field:not(#main).error select,
+.field:not(#main).error textarea,
+.field:not(#main).invalid input,
+.field:not(#main).invalid select,
+.field:not(#main).invalid textarea {
+ border-color: var(--error) !important;
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
+}
-table.tenant-members tbody td:nth-child(2) {
- font-size: 14pt;
- font-weight: bold;
+/* Help text below inputs */
+.field:not(#main) p.help {
+ font-size: 12px;
+ color: var(--text-tertiary);
+ margin: 6px 0 0;
+ line-height: 1.5;
+ font-style: italic;
}
-table.tenant-members tbody .role {
- cursor: pointer;
+
+.field:not(#main) p.help em {
+ font-style: normal;
+ color: var(--accent-light);
+ font-weight: 600;
}
-.roles-menu {
- width: 300px;
- border: 1px solid #ccc;
- border-top-width: 0;
+.field:not(#main) p.help .example {
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
+ font-size: 11px;
+ color: var(--accent-light);
+ background-color: var(--bg-elevated);
+ border: 1px solid var(--border-default);
+ padding: 1px 6px;
+ border-radius: 4px;
+ font-style: normal;
}
-.roles-menu > div {
- border-top: 1px solid #ccc;
- padding: 11pt;
- background: linear-gradient(#fff,#eee);
- cursor: pointer;
+
+/* Plugin section header (.l1) */
+.l1 {
+ overflow: hidden;
+ padding: 1.25rem 0 0.25rem;
}
-.roles-menu > div.current {
- background: linear-gradient(lightcyan,lightblue);
+
+.l1 h3 {
+ font-size: 14px;
+ font-weight: 700;
+ color: var(--text-secondary);
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid var(--border-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
}
-.roles-menu strong {
- font-weight: bold;
- font-size: 12pt;
+
+.l1 h3 strong {
+ color: var(--accent-light);
+ text-transform: none;
+ letter-spacing: 0;
+ font-size: 16px;
}
-.roles-menu p {
- margin: 0.5em 0;
- color: #555;
+
+/* ================================================
+ WIZARD — Band (row separator in review/forms)
+ ================================================ */
+
+.c12.band {
+ padding: 0.25rem 0;
}
-.ctl .widget .invite {
- display: block;
- font-size: 14pt;
- width: 60%;
- box-sizing: border-box;
- margin-bottom: 0;
+/* ================================================
+ WIZARD — Button Bar
+ ================================================ */
+
+.buttons {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ align-items: center;
+ padding: 1.25rem 0 0.25rem;
+ overflow: hidden;
+ clear: both;
}
-.userlookup-results {
- border: 1px solid #ccc;
- position: relative;
- top: -1px;
- background-color: #ffe;
- width: 60%;
- box-sizing: border-box;
+.buttons button[rel="prev"] {
+ background-color: transparent;
+ color: var(--text-secondary);
+ border: 1px solid var(--border-default);
+ order: 0;
}
-.userlookup-results li {
- border-bottom: 1px solid #ccc;
- padding: 6px;
- background: linear-gradient(#fff,#eee);
- cursor: pointer;
+
+.buttons button[rel="prev"]:hover:not(:disabled) {
+ background-color: var(--bg-tertiary);
+ color: var(--text-primary);
+ transform: none;
+ box-shadow: none;
}
-.userlookup-results li:hover {
- background: linear-gradient(lightcyan,lightblue);
+
+.buttons button[rel="next"],
+.buttons button.final {
+ order: 1;
+ margin-left: auto;
}
-.userlookup-results strong {
- font-weight: bold;
+
+.buttons button span {
+ font-weight: 700;
}
-.userlookup-results p {
+
+/* ================================================
+ WIZARD — Schedule Widget
+ ================================================ */
+
+/* Pill option groups (Hourly / Daily / Weekly / Monthly, AM/PM, weekdays) */
+ul.optgroup {
+ display: inline-flex;
+ flex-wrap: wrap;
+ gap: 4px;
+ padding: 0;
margin: 0;
- float: right;
+ list-style: none;
+ vertical-align: middle;
}
-td span.role {
- background: url(/i/dropdown.png) no-repeat 0% 40%;
- padding-left: 14px;
- display: inline-block;
+ul.optgroup li {
+ padding: 6px 16px;
+ border-radius: var(--radius-md);
+ background-color: var(--bg-tertiary);
+ border: 1px solid var(--border-default);
+ color: var(--text-secondary);
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ user-select: none;
+ transition: all 0.15s ease;
}
-#logging-in {
- position: fixed;
- background-color: rgba(255,255,255,0.9);
- z-index: 150;
- width: 100%;
- height: 100%;
-}
-#logging-in p {
- margin: 20% auto;
- width: 100%;
- background-color: #fff;
- box-shadow: 4px 0px 10px rgba(0,0,0,0.25);
- padding: 1em;
- text-align: center;
-}
-#logging-in p span {
- font-weight: bold;
- color: #0071bc;
-}
-#logging-in p img {
- display: inline;
- height: 1em;
+ul.optgroup li:hover {
+ background-color: var(--bg-elevated);
+ color: var(--text-primary);
+ border-color: var(--accent-primary);
}
-#cliauth #creds {
- display: inline-block;
- background-color: #000;
- font-family: monospace;
- padding: 1em;
- font-size: 16px;
- color: yellow;
+ul.optgroup li.selected {
+ background-color: var(--accent-primary);
+ border-color: var(--accent-primary);
+ color: #fff;
+ font-weight: 600;
}
-#fixed-wrapper {
- overflow: scroll;
+/* Compact variants used inline */
+ul.ampm.optgroup li,
+ul.wday.optgroup li,
+ul.mday.optgroup li {
+ padding: 4px 10px;
+ font-size: 12px;
}
-#fixed-wrapper #fixedkey {
- display: inline-block;
- background-color: #000;
- font-family: monospace;
- padding: 1em;
- font-size: 16px;
- width: 63%;
- white-space: pre-wrap;
- word-wrap: break-word;
- color: yellow;
+/* Schedule card container */
+.scheduling {
+ background-color: var(--bg-card);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+ padding: 1rem 1.25rem;
}
-#fixed-wrapper #accept {
- height: 40px;
- width: 150px;
- margin: -20px -75px;
- position: relative;
- top: 50%;
- left: 50%;
- background-color: #ffff00;
- color: #000;
- font-size: 16px;
- font-family: monospace;
- border-radius: 5px;
- cursor: pointer;
- margin-bottom: 0px;
- font-weight: bold;
+/* Frequency type chooser row */
+.scheduling > ul.optgroup {
+ margin-bottom: 0;
}
-.large-checkbox {
- transform: scale(1.75);
- margin: 14px 20px;
+/* Sub-form panels (hourly/daily/weekly/monthly detail) */
+.scheduling .subform {
+ display: none;
+ padding-top: 0.875rem;
+ margin-top: 0.875rem;
+ border-top: 1px solid var(--border-muted);
}
-#dr-explain {
- font-size: 12pt;
- padding: 2em;
+.scheduling .subform > div {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+ font-size: 14px;
+ color: var(--text-secondary);
+ margin-bottom: 6px;
}
-.notice {
- background-color: #b2e1ff;
- padding: 1em;
- border-radius: 0.5em;
- font-size: 11pt;
-}
-h2 strong,
-.notice strong {
- font-weight: bold;
- color: #0071bc;
-}
-.notice.failure {
- background-color: #FF6161;
- color: #fff;
- font-size: 120%;
- line-height: 1.4em;
+.scheduling .subform > div:last-child {
+ margin-bottom: 0;
}
-#user-agent{
- max-width: 200px;
+.scheduling p.help {
+ margin-top: 0.75rem;
+ font-size: 12px;
+ color: var(--text-tertiary);
+ font-style: italic;
}
-.scheduling .optgroup {
+/* ================================================
+ WIZARD — Toggle Switch
+ ================================================ */
+
+.switch {
+ position: relative;
display: inline-block;
+ width: 46px;
+ height: 24px;
+ vertical-align: middle;
+ flex-shrink: 0;
}
-.scheduling .optgroup li {
- display: inline-block;
- padding: 8px 6px 6px 6px;
- border: 1px solid #0071bc;
- border-radius: 4px;
- opacity: 0.6;
- color: #0071bc;
- margin: 11px 2px;
- line-height: 0.8em;
- cursor: pointer;
- background-color: #fff;
+.switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ position: absolute;
}
-.scheduling .optgroup li.selected {
- background-color: #0071bc;
- opacity: 1;
- color: #fff;
- font-weight: bold;
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ inset: 0;
+ background-color: var(--bg-elevated);
+ border: 1px solid var(--border-default);
+ transition: background-color 0.25s ease, border-color 0.25s ease;
}
-.scheduling input.num,
-.scheduling input.time {
- border: none;
- border-bottom: 2px solid #0071bc;
- font-size: 18pt;
- text-align: center;
+
+.slider::before {
+ content: "";
+ position: absolute;
+ width: 16px;
+ height: 16px;
+ left: 3px;
+ top: 3px;
+ background-color: var(--text-tertiary);
+ transition: transform 0.25s ease, background-color 0.25s ease;
}
-.scheduling input.num {
- width: 4ex;
+
+.switch input:checked + .slider {
+ background-color: var(--accent-primary);
+ border-color: var(--accent-primary);
}
-.scheduling input.time {
- width: 6ex;
+
+.switch input:checked + .slider::before {
+ background-color: #fff;
+ transform: translateX(22px);
}
-.scheduling .subform {
- display: none;
+
+.switch input:focus-visible + .slider {
+ outline: 2px solid var(--accent-primary);
+ outline-offset: 2px;
}
-redacted {
- background-color: transparent;
- color: inherit;
- filter: blur(10px);
- font-weight: 900;
+.slider.round {
+ border-radius: 24px;
}
-redacted:hover {
- filter: none;
- font-weight: inherit
+.slider.round::before {
+ border-radius: 50%;
}
+/* ================================================
+ WIZARD — Side Help Panel
+ ================================================ */
+
+.side-help {
+ background-color: var(--bg-card);
+ border: 1px solid var(--border-default);
+ border-left: 3px solid var(--accent-primary);
+ border-radius: var(--radius-md);
+ padding: 1rem 1.25rem;
+ font-size: 13px;
+ color: var(--text-secondary);
+ line-height: 1.6;
+ margin-top: 1rem;
+}
+/* ================================================
+ WIZARD — "Awaiting Plugin Selection" message
+ ================================================ */
-.redraw .deferred {
- text-align: center;
- display: block;
- font-size: 14px;
+p.awaiting-selection {
+ font-size: 13px;
+ color: var(--text-tertiary);
font-style: italic;
- color: #aaa;
- padding: 12px 0;
+ padding: 0.75rem 1rem;
+ background-color: var(--bg-tertiary);
+ border: 1px dashed var(--border-default);
+ border-radius: var(--radius-md);
+ margin: 0;
}
-.locked {
- background-color: darkred;
- color: #fff;
- padding: 2em;
- display: none;
-}
-.locked h1 {
- font-size: 36px;
- font-weight: bold;
-}
-.locked p {
- font-size: 20px;
- width: 27em;
- margin: 1.3em 0;
- line-height: 1.2em;
+/* ================================================
+ WIZARD — Smudge (password reveal) field
+ ================================================ */
+
+.smudge {
+ position: relative;
+ display: block;
}
-.locked form * {
- font-size: 20px;
+.smudge input {
+ padding-right: 56px;
}
-.locked form input {
- background-color: #111;
- color: #fff;
- padding: 8px 24px;
- border-radius: 8px 0 0 8px;
- border: none;
- border-right: 1px solid #666;
- width: 25em;
- max-width: 70%;
+
+.smudge > span {
+ position: absolute;
+ right: 12px;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 11px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ color: var(--accent-primary);
+ cursor: pointer;
+ user-select: none;
+ transition: color 0.15s ease;
}
-.locked form button {
- background-color: #222;
- color: #fff;
- border: 0;
- padding: 8px 24px;
- border-radius: 0 8px 8px 0;
+
+.smudge > span:hover {
+ color: var(--accent-light);
}
+/* ================================================
+ WIZARD — Intro step copy
+ ================================================ */
-table th.sortable {
- cursor: pointer;
+.intro > p {
+ font-size: 15px;
+ color: var(--text-secondary);
+ line-height: 1.7;
+ margin-bottom: 1.25rem;
+ max-width: 65ch;
}
-table th.sortable.asc ::before,
-table th.sortable.desc ::before {
- margin-left: 4px;
- content: "\25b4";
- display: inline-block;
- opacity: 0.4;
- font-size: 11pt;
+
+/* ================================================
+ WIZARD — Review (step 5) summary cards
+ ================================================ */
+
+.summary-section {
+ background-color: var(--bg-card);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+ overflow: hidden;
+ margin: 0 0 1.5rem;
+ box-shadow: var(--shadow-sm);
}
-table th.sortable.asc ::before {
- transform: rotate(180deg);
+
+.summary-section > .c12.band {
+ border-bottom: 1px solid var(--border-muted);
+ padding: 0.875rem 1.5rem;
+ overflow: hidden;
}
+.summary-section > .c12.band:last-of-type {
+ border-bottom: none;
+}
-.denied {
- font-style: italic;
- color: #999;
- font-size: 12px;
- padding: 0em 3em;
+.summary-section label {
display: block;
+ font-size: 11px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.6px;
+ color: var(--text-tertiary);
+ padding-top: 2px;
}
-a.load-more {
- text-decoration: none;
- color: #555;
- display: block;
- border: 1px solid #ccc;
- padding: 2em;
- margin: 1em auto;
- width: 10em;
- text-align: center;
- border-radius: 1em;
+p.selected-elsewhere {
+ font-size: 14px;
+ color: var(--text-primary);
+ margin: 0;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+ line-height: 1.5;
}
-h3 strong { color: #0071bc; }
+a.change-me {
+ font-size: 11px;
+ color: var(--accent-primary);
+ text-decoration: none;
+ border: 1px solid var(--border-default);
+ padding: 2px 10px;
+ border-radius: var(--radius-sm);
+ margin-left: auto;
+ white-space: nowrap;
+ transition: all 0.15s ease;
+ font-weight: 600;
+}
+a.change-me:hover {
+ background-color: var(--accent-primary);
+ border-color: var(--accent-primary);
+ color: #fff;
+}
-.cant-go-further {
- display: block;
- background-color: firebrick;
+.review .tag,
+.summary-section .tag {
+ background-color: var(--success);
color: #fff;
- padding: 0.1em 1em;
- width: 100%;
+ border-radius: 4px;
+ font-size: 11px;
+ font-weight: 700;
+ padding: 2px 8px;
+ letter-spacing: 0.3px;
+ text-transform: uppercase;
+ flex-shrink: 0;
}
-.lean.hidden tbody tr td {
- opacity: 0.5;
- font-weight: normal;
+/* Selectable table row "Define a new..." footer row */
+table.lean tbody tr td[rel="new"] {
+ text-align: center;
+ color: var(--accent-primary);
+ font-size: 13px;
font-style: italic;
+ cursor: pointer;
+ padding: 12px;
+ border-top: 1px solid var(--border-muted);
+ transition: background-color 0.15s ease, color 0.15s ease;
}
+table.lean tbody tr td[rel="new"]:hover {
+ background-color: rgba(59, 130, 246, 0.06);
+ color: var(--accent-light);
+}
-.lean.fixups .identity {
- font-size: 18px;
- font-weight: bold;
+/* Selectable table selected row highlight */
+table.lean.selectable tbody tr.selected td {
+ background-color: rgba(59, 130, 246, 0.1);
+ border-color: var(--accent-primary);
}
-.lean.fixups .identity > span {
- display: block;
- font-size: 12px;
- font-family: monospace;
- font-weight: normal;
+
+table.lean.selectable tbody tr {
+ cursor: pointer;
+}
+
+table.lean thead th,
+table.lean tbody td {
+ padding: 12px 16px;
+ font-size: 14px;
+ border-bottom: 1px solid var(--border-muted);
+ text-align: left;
}
-.lean {
- line-height: 1.2em;
+table.lean thead th {
+ font-weight: 600;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ color: var(--text-tertiary);
+ background-color: var(--bg-tertiary);
}
-.lean.fixups code {
- font-weight: bold;
- font-family: monospace;
- padding: 2pt 3pt;
- border-radius: 4pt;
- background-color: rgba(0,0,0, 0.05);
- border: 1px solid rgba(0,0,0, 0.15);
+
+table.lean {
+ width: 100%;
+ background-color: var(--bg-card);
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-lg);
+ overflow: hidden;
+ box-shadow: var(--shadow-sm);
+ border-collapse: separate;
+ border-spacing: 0;
}
-.lean.fixups a[href^="apply-fixup:"] {
- white-space: nowrap;
+
+table.lean tbody tr:hover td {
+ background-color: var(--bg-tertiary);
}
-.paginate .loading {
- display: none;
+table.lean tbody tr:last-child td {
+ border-bottom: none;
}