MokoOnyx v01.00.00 — initial release (successor to MokoCassiopeia)
Some checks failed
Standards Compliance / Secret Scanning (push) Successful in 3s
Standards Compliance / License Header Validation (push) Successful in 4s
Standards Compliance / Repository Structure Validation (push) Successful in 5s
Standards Compliance / Coding Standards Check (push) Failing after 3s
Standards Compliance / Version Consistency Check (push) Successful in 3s
Standards Compliance / Workflow Configuration Check (push) Failing after 2s
Standards Compliance / Documentation Quality Check (push) Successful in 3s
Standards Compliance / README Completeness Check (push) Successful in 3s
Standards Compliance / Git Repository Hygiene (push) Successful in 2s
Standards Compliance / Script Integrity Validation (push) Successful in 4s
Standards Compliance / Line Length Check (push) Failing after 4s
Standards Compliance / File Naming Standards (push) Successful in 2s
Standards Compliance / Insecure Code Pattern Detection (push) Successful in 3s
Standards Compliance / Code Complexity Analysis (push) Successful in 3s
Standards Compliance / Code Duplication Detection (push) Successful in 4s
Standards Compliance / Dead Code Detection (push) Successful in 3s
Standards Compliance / File Size Limits (push) Successful in 2s
CodeQL Security Scanning / Analyze (javascript) (push) Failing after 1m9s
Standards Compliance / Binary File Detection (push) Successful in 4s
CodeQL Security Scanning / Analyze (actions) (push) Failing after 1m11s
Standards Compliance / TODO/FIXME Tracking (push) Successful in 3s
Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 5s
Standards Compliance / Broken Link Detection (push) Successful in 5s
Standards Compliance / Unused Dependencies Check (push) Successful in 7s
Standards Compliance / API Documentation Coverage (push) Successful in 3s
Standards Compliance / Accessibility Check (push) Successful in 3s
Standards Compliance / Performance Metrics (push) Successful in 3s
Standards Compliance / Enterprise Readiness Check (push) Successful in 3s
Standards Compliance / Repository Health Check (push) Successful in 4s
Standards Compliance / Terraform Configuration Validation (push) Successful in 6s
CodeQL Security Scanning / Security Scan Summary (push) Successful in 1s
Standards Compliance / Compliance Summary (push) Successful in 1s
Repo Health / Access control (push) Successful in 1s
Auto-Update SHA Hash / Update SHA-256 Hash in updates.xml (release) Successful in 4s
Repo Health / Release configuration (push) Failing after 3s
Repo Health / Scripts governance (push) Successful in 3s
Repo Health / Repository health (push) Failing after 3s

All files renamed from mokocassiopeia to mokoonyx.
Update server points to MokoOnyx repo.
Bridge migration removed (clean standalone template).
Version reset to 01.00.00.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan Miller
2026-04-19 17:19:03 -05:00
parent 3ba2214614
commit 8258ed804a
238 changed files with 85443 additions and 2 deletions

View File

@@ -0,0 +1,227 @@
@charset "UTF-8";
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: Joomla.Template.Site
* INGROUP: MokoOnyx.Accessibility
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx
* PATH: ./media/css/a11y-high-contrast.css
* VERSION: 03.09.14
* BRIEF: High-contrast stylesheet for accessibility toolbar
*/
/* ===================================================================
* HIGH CONTRAST MODE
* Applied when .a11y-high-contrast is on <html>.
* Overrides theme variables to maximise contrast ratios (WCAG AAA).
* =================================================================== */
/* ── Light mode high contrast ─────────────────────────────────────── */
:root[data-bs-theme="light"].a11y-high-contrast {
--body-color: #000;
--body-color-rgb: 0, 0, 0;
--body-bg: #fff;
--body-bg-rgb: 255, 255, 255;
--heading-color: #000;
--emphasis-color: #000;
--secondary-color: #000000bf;
--tertiary-color: #00000080;
--muted-color: #333;
/* Links — strong blue on white */
--color-link: #0000ee;
--link-color: #0000ee;
--link-color-rgb: 0, 0, 238;
--color-hover: #cc0000;
--link-hover-color: #cc0000;
--link-hover-color-rgb: 204, 0, 0;
/* Borders — visible on all backgrounds */
--border-color: #000;
--border-color-soft: #333;
/* Backgrounds */
--secondary-bg: #e0e0e0;
--secondary-bg-rgb: 224, 224, 224;
--tertiary-bg: #f0f0f0;
--tertiary-bg-rgb: 240, 240, 240;
/* Navigation */
--nav-bg-color: #000;
--nav-text-color: #fff;
--mainmenu-nav-link-color: #fff;
/* Buttons */
--btn-color: #fff;
--btn-bg: #000;
--btn-border-color: #000;
--btn-hover-color: #000;
--btn-hover-bg: #ffff00;
--btn-hover-border-color: #000;
--btn-active-color: #000;
--btn-active-bg: #ffff00;
--btn-active-border-color: #000;
/* Forms */
--input-color: #000;
--input-bg: #fff;
--input-border-color: #000;
--input-focus-color: #000;
--input-focus-bg: #ffffcc;
--input-focus-border-color: #0000ee;
--input-placeholder-color: #555;
/* Cards */
--card-border-color: #000;
--card-bg: #fff;
--card-cap-bg: #e0e0e0;
/* Tables */
--table-color: #000;
--table-bg: #fff;
--table-border-color: #000;
--table-striped-bg: #f0f0f0;
--table-hover-bg: #ffff99;
/* Alerts */
--alert-border-width: 2px;
/* Code */
--code-color: #000;
--code-bg-color: #ffffcc;
/* Selection */
--selection-bg: #0000ee;
--selection-ink: #fff;
/* Focus indicator — always visible */
--focus-ring-color: #0000ee;
--focus-ring-width: 3px;
}
/* ── Dark mode high contrast ──────────────────────────────────────── */
:root[data-bs-theme="dark"].a11y-high-contrast {
--body-color: #fff;
--body-color-rgb: 255, 255, 255;
--body-bg: #000;
--body-bg-rgb: 0, 0, 0;
--heading-color: #fff;
--emphasis-color: #fff;
--secondary-color: #ffffffbf;
--tertiary-color: #ffffff80;
--muted-color: #ccc;
/* Links — bright yellow on black */
--color-link: #ffff00;
--link-color: #ffff00;
--link-color-rgb: 255, 255, 0;
--color-hover: #00ffff;
--link-hover-color: #00ffff;
--link-hover-color-rgb: 0, 255, 255;
/* Borders */
--border-color: #fff;
--border-color-soft: #ccc;
/* Backgrounds */
--secondary-bg: #1a1a1a;
--secondary-bg-rgb: 26, 26, 26;
--tertiary-bg: #111;
--tertiary-bg-rgb: 17, 17, 17;
/* Navigation */
--nav-bg-color: #000;
--nav-text-color: #fff;
--mainmenu-nav-link-color: #ffff00;
/* Buttons */
--btn-color: #000;
--btn-bg: #ffff00;
--btn-border-color: #ffff00;
--btn-hover-color: #000;
--btn-hover-bg: #00ffff;
--btn-hover-border-color: #00ffff;
--btn-active-color: #000;
--btn-active-bg: #00ffff;
--btn-active-border-color: #00ffff;
/* Forms */
--input-color: #fff;
--input-bg: #000;
--input-border-color: #fff;
--input-focus-color: #fff;
--input-focus-bg: #1a1a1a;
--input-focus-border-color: #ffff00;
--input-placeholder-color: #aaa;
/* Cards */
--card-border-color: #fff;
--card-bg: #000;
--card-cap-bg: #1a1a1a;
/* Tables */
--table-color: #fff;
--table-bg: #000;
--table-border-color: #fff;
--table-striped-bg: #111;
--table-hover-bg: #333;
/* Alerts */
--alert-border-width: 2px;
/* Code */
--code-color: #00ff00;
--code-bg-color: #1a1a1a;
/* Selection */
--selection-bg: #ffff00;
--selection-ink: #000;
/* Focus indicator */
--focus-ring-color: #ffff00;
--focus-ring-width: 3px;
}
/* ── Shared high-contrast overrides (both modes) ──────────────────── */
.a11y-high-contrast * {
border-color: var(--border-color) !important;
}
.a11y-high-contrast *:focus-visible {
outline: var(--focus-ring-width, 3px) solid var(--focus-ring-color, #0000ee) !important;
outline-offset: 2px !important;
}
.a11y-high-contrast img {
outline: 2px solid var(--border-color);
}
.a11y-high-contrast a {
text-decoration: underline !important;
text-decoration-thickness: 2px !important;
}
.a11y-high-contrast button,
.a11y-high-contrast .btn,
.a11y-high-contrast input,
.a11y-high-contrast select,
.a11y-high-contrast textarea {
border-width: 2px !important;
border-style: solid !important;
}
.a11y-high-contrast .badge,
.a11y-high-contrast .alert {
border: 2px solid var(--border-color) !important;
}
/* Ensure disabled states are still distinguishable */
.a11y-high-contrast [disabled],
.a11y-high-contrast .disabled {
opacity: .5 !important;
text-decoration: line-through !important;
}

79
src/media/css/editor.css Normal file
View File

@@ -0,0 +1,79 @@
@charset "UTF-8";
/* Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
*/
/* STYLES FOR JOOMLA! EDITOR */
body {
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #22262a;
background-color: #fff;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 700;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
a {
text-decoration: none;
}
a:link {
color: #224faa;
}
a:hover {
color: #424077;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
/* STYLES FOR JOOMLA! EDITOR */
hr#system-readmore {
color: #f00;
border: #f00 dashed 1px;
}
span[lang] {
padding: 2px;
border: 1px dashed #bbb;
}
span[lang]:after {
font-size: smaller;
color: #f00;
vertical-align: super;
content: attr(lang);
}

1
src/media/css/editor.min.css vendored Normal file
View File

@@ -0,0 +1 @@
@charset "UTF-8";body{font-size:1rem;font-weight:400;line-height:1.5;color:#22262a;background-color:#fff}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:700;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}h2{font-size:calc(1.325rem + .9vw)}h3{font-size:calc(1.3rem + .6vw)}h4{font-size:calc(1.275rem + .3vw)}h5{font-size:1.25rem}h6{font-size:1rem}a{text-decoration:none}a:link{color:#224faa}a:hover{color:#424077}p{margin-top:0;margin-bottom:1rem}hr#system-readmore{color:red;border:1px dashed red}span[lang]{padding:2px;border:1px dashed #bbb}span[lang]:after{font-size:smaller;color:red;vertical-align:super;content:attr(lang)}

View File

@@ -0,0 +1,10 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Fredoka — self-hosted from src/media/fonts/
*/
@font-face { font-family: 'Fredoka'; font-style: normal; font-weight: 300; font-display: swap; src: url('../../fonts/fredoka-v17-latin-300.woff2') format('woff2'); }
@font-face { font-family: 'Fredoka'; font-style: normal; font-weight: 400; font-display: swap; src: url('../../fonts/fredoka-v17-latin-regular.woff2') format('woff2'); }
@font-face { font-family: 'Fredoka'; font-style: normal; font-weight: 500; font-display: swap; src: url('../../fonts/fredoka-v17-latin-500.woff2') format('woff2'); }
@font-face { font-family: 'Fredoka'; font-style: normal; font-weight: 600; font-display: swap; src: url('../../fonts/fredoka-v17-latin-600.woff2') format('woff2'); }
@font-face { font-family: 'Fredoka'; font-style: normal; font-weight: 700; font-display: swap; src: url('../../fonts/fredoka-v17-latin-700.woff2') format('woff2'); }

View File

@@ -0,0 +1,14 @@
/* Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
*/
@font-face {
font-family: 'Osaka';
src: url('../../fonts/osaka-re.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}

View File

@@ -0,0 +1,6 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Pacifico — self-hosted from src/media/fonts/
*/
@font-face { font-family: 'Pacifico'; font-style: normal; font-weight: 400; font-display: swap; src: url('../../fonts/pacifico-v23-latin-regular.woff2') format('woff2'); }

View File

@@ -0,0 +1,23 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Roboto — self-hosted from src/media/fonts/
*/
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 100; font-display: swap; src: url('../../fonts/roboto-v51-latin-100.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 100; font-display: swap; src: url('../../fonts/roboto-v51-latin-100italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 200; font-display: swap; src: url('../../fonts/roboto-v51-latin-200.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 200; font-display: swap; src: url('../../fonts/roboto-v51-latin-200italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 300; font-display: swap; src: url('../../fonts/roboto-v51-latin-300.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 300; font-display: swap; src: url('../../fonts/roboto-v51-latin-300italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 400; font-display: swap; src: url('../../fonts/roboto-v51-latin-regular.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 400; font-display: swap; src: url('../../fonts/roboto-v51-latin-italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 500; font-display: swap; src: url('../../fonts/roboto-v51-latin-500.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 500; font-display: swap; src: url('../../fonts/roboto-v51-latin-500italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 600; font-display: swap; src: url('../../fonts/roboto-v51-latin-600.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 600; font-display: swap; src: url('../../fonts/roboto-v51-latin-600italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 700; font-display: swap; src: url('../../fonts/roboto-v51-latin-700.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 700; font-display: swap; src: url('../../fonts/roboto-v51-latin-700italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 800; font-display: swap; src: url('../../fonts/roboto-v51-latin-800.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 800; font-display: swap; src: url('../../fonts/roboto-v51-latin-800italic.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 900; font-display: swap; src: url('../../fonts/roboto-v51-latin-900.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-style: italic; font-weight: 900; font-display: swap; src: url('../../fonts/roboto-v51-latin-900italic.woff2') format('woff2'); }

76
src/media/css/index.html Normal file
View File

@@ -0,0 +1,76 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Redirecting…</title>
<!-- Search engines: do not index this placeholder redirect page -->
<meta name="robots" content="noindex, nofollow, noarchive" />
<!-- Instant redirect fallback even if JavaScript is disabled -->
<meta http-equiv="refresh" content="0; url=/" />
<!-- Canonical root reference -->
<link rel="canonical" href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
(function redirectToRoot() {
// Configuration object with safe defaults.
var opts = {
fallbackPath: "/", // string: fallback destination if origin is unavailable
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
behavior: "replace" // enum: "replace" | "assign"
};
// Determine absolute origin in all mainstream browsers.
var origin = (typeof location.origin === "string" && location.origin)
|| (location.protocol + "//" + location.host);
// Final destination: absolute root of the current site, or fallback path.
var destination = origin ? origin + "/" : opts.fallbackPath;
function go() {
if (opts.behavior === "assign") {
location.assign(destination);
} else {
location.replace(destination);
}
}
// Execute redirect, optionally after a short delay.
if (opts.delayMs > 0) {
setTimeout(go, opts.delayMs);
} else {
go();
}
})();
</script>
<!--
Secondary meta-refresh for no-JS environments is already set above.
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
-->
<noscript>
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
<style>
html, body { height:100%; }
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
.msg { opacity: .75; text-align: center; }
</style>
</noscript>
</head>
<body>
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
</body>
</html>

258
src/media/css/offline.css Normal file
View File

@@ -0,0 +1,258 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
*/
/* === Offline Page — Full-viewport background with centered overlay card === */
.moko-offline-wrap {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem 1rem;
color: #fff;
font-family: var(--body-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);
/* Background: offline_image set inline, or fall back to header background */
background-color: var(--color-primary, #112855);
background-image: var(--header-background-image, none);
background-position: var(--header-background-position, center);
background-attachment: var(--header-background-attachment, fixed);
background-repeat: no-repeat;
background-size: cover;
}
/* Dark theme: overlay to darken the background */
:root[data-bs-theme="dark"] .moko-offline-wrap {
position: relative;
}
:root[data-bs-theme="dark"] .moko-offline-wrap::before {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 0;
}
/* === Centered Card Overlay === */
.moko-offline-card {
width: 100%;
max-width: 720px;
background: var(--offline-card-bg, rgba(0, 0, 0, 0.6));
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border-radius: 0.875rem;
padding: 2.5rem 2rem;
text-align: center;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
@media (min-width: 768px) {
.moko-offline-card {
padding: 3rem;
}
}
@media (max-width: 575.98px) {
.moko-offline-wrap {
padding: 1rem 0.75rem;
}
.moko-offline-card {
padding: 2rem 1.25rem;
}
}
/* === Logo header area === */
.moko-offline-brand {
display: block;
text-align: center;
text-decoration: none;
color: #fff;
margin-bottom: 1.5rem;
}
.moko-offline-brand:hover {
color: var(--accent-color-primary, #3f8ff0);
}
.moko-offline-brand img {
max-width: 100%;
height: auto;
}
.moko-offline-brand .site-title {
display: block;
font-size: 2rem;
font-weight: 700;
font-family: 'Osaka', var(--body-font-family, sans-serif);
color: var(--accent-color-secondary, #6fb3ff);
}
.moko-offline-brand .brand-tagline {
display: block;
opacity: 0.7;
font-size: 0.9rem;
margin-top: 0.25rem;
}
/* === Offline Message === */
.moko-offline-message {
margin-bottom: 1.5rem;
}
.moko-offline-message h1 {
font-size: 1.5rem;
font-weight: 700;
color: #fff;
margin-bottom: 0.5rem;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
.moko-offline-message p {
color: rgba(255, 255, 255, 0.85);
line-height: 1.6;
margin: 0;
}
/* === Offline Module Position === */
.moko-offline-modules {
margin-bottom: 1.5rem;
text-align: left;
}
/* === Copyright Footer === */
.moko-offline-copyright {
font-size: 0.8rem;
color: rgba(255, 255, 255, 0.45);
margin-top: 1.5rem;
padding-top: 1rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.moko-offline-copyright a {
color: rgba(255, 255, 255, 0.6);
text-decoration: underline;
}
.moko-offline-copyright a:hover {
color: #fff;
}
/* === Login Accordion (translucent on overlay) === */
.moko-offline-card .accordion {
text-align: left;
}
.moko-offline-card .accordion-item {
background: transparent;
border-color: rgba(255, 255, 255, 0.15);
}
.moko-offline-card .accordion-button {
background: transparent;
color: rgba(255, 255, 255, 0.8);
font-size: 0.9rem;
padding: 0.75rem 1rem;
}
.moko-offline-card .accordion-button:not(.collapsed) {
background: rgba(255, 255, 255, 0.05);
color: #fff;
box-shadow: none;
}
.moko-offline-card .accordion-button::after {
filter: invert(1) brightness(2);
}
.moko-offline-card .accordion-body {
background: transparent;
padding: 1rem;
}
/* === Form Controls (glass effect) === */
.moko-offline-card .form-control {
background-color: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.2);
color: #fff;
}
.moko-offline-card .form-control::placeholder {
color: rgba(255, 255, 255, 0.4);
}
.moko-offline-card .form-control:focus {
background-color: rgba(255, 255, 255, 0.15);
border-color: var(--accent-color-primary, #3f8ff0);
color: #fff;
box-shadow: 0 0 0 0.25rem rgba(63, 143, 240, 0.25);
}
.moko-offline-card .form-label {
color: rgba(255, 255, 255, 0.8);
font-size: 0.875rem;
}
.moko-offline-card .form-check-label {
color: rgba(255, 255, 255, 0.7);
}
.moko-offline-card .form-check-input {
background-color: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.3);
}
.moko-offline-card .form-check-input:checked {
background-color: var(--accent-color-primary, #3f8ff0);
border-color: var(--accent-color-primary, #3f8ff0);
}
/* === Button === */
.moko-offline-card .btn-primary {
background-color: var(--color-primary, #112855);
border-color: rgba(255, 255, 255, 0.15);
color: #fff;
}
.moko-offline-card .btn-primary:hover {
background-color: var(--accent-color-primary, #3f8ff0);
border-color: var(--accent-color-primary, #3f8ff0);
}
/* === Links === */
.moko-offline-card a {
color: var(--accent-color-primary, #3f8ff0);
}
.moko-offline-card a:hover {
color: #fff;
}
/* === Joomla system messages === */
.moko-offline-messages {
width: 100%;
max-width: 720px;
margin-bottom: 1rem;
}
/* === Skip Link === */
.skip-link {
position: absolute;
left: -9999px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}
.skip-link:focus {
position: static;
width: auto;
height: auto;
padding: 0.5rem 1rem;
}

View File

@@ -0,0 +1,76 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Redirecting…</title>
<!-- Search engines: do not index this placeholder redirect page -->
<meta name="robots" content="noindex, nofollow, noarchive" />
<!-- Instant redirect fallback even if JavaScript is disabled -->
<meta http-equiv="refresh" content="0; url=/" />
<!-- Canonical root reference -->
<link rel="canonical" href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
(function redirectToRoot() {
// Configuration object with safe defaults.
var opts = {
fallbackPath: "/", // string: fallback destination if origin is unavailable
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
behavior: "replace" // enum: "replace" | "assign"
};
// Determine absolute origin in all mainstream browsers.
var origin = (typeof location.origin === "string" && location.origin)
|| (location.protocol + "//" + location.host);
// Final destination: absolute root of the current site, or fallback path.
var destination = origin ? origin + "/" : opts.fallbackPath;
function go() {
if (opts.behavior === "assign") {
location.assign(destination);
} else {
location.replace(destination);
}
}
// Execute redirect, optionally after a short delay.
if (opts.delayMs > 0) {
setTimeout(go, opts.delayMs);
} else {
go();
}
})();
</script>
<!--
Secondary meta-refresh for no-JS environments is already set above.
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
-->
<noscript>
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
<style>
html, body { height:100%; }
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
.msg { opacity: .75; text-align: center; }
</style>
</noscript>
</head>
<body>
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
</body>
</html>

View File

@@ -0,0 +1,76 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Redirecting…</title>
<!-- Search engines: do not index this placeholder redirect page -->
<meta name="robots" content="noindex, nofollow, noarchive" />
<!-- Instant redirect fallback even if JavaScript is disabled -->
<meta http-equiv="refresh" content="0; url=/" />
<!-- Canonical root reference -->
<link rel="canonical" href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
(function redirectToRoot() {
// Configuration object with safe defaults.
var opts = {
fallbackPath: "/", // string: fallback destination if origin is unavailable
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
behavior: "replace" // enum: "replace" | "assign"
};
// Determine absolute origin in all mainstream browsers.
var origin = (typeof location.origin === "string" && location.origin)
|| (location.protocol + "//" + location.host);
// Final destination: absolute root of the current site, or fallback path.
var destination = origin ? origin + "/" : opts.fallbackPath;
function go() {
if (opts.behavior === "assign") {
location.assign(destination);
} else {
location.replace(destination);
}
}
// Execute redirect, optionally after a short delay.
if (opts.delayMs > 0) {
setTimeout(go, opts.delayMs);
} else {
go();
}
})();
</script>
<!--
Secondary meta-refresh for no-JS environments is already set above.
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
-->
<noscript>
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
<style>
html, body { height:100%; }
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
.msg { opacity: .75; text-align: center; }
</style>
</noscript>
</head>
<body>
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
</body>
</html>

View File

@@ -0,0 +1,57 @@
@charset "UTF-8";
/* Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
*/
.js-stools-container-bar {
padding: 10px 20px;
}
.js-stools-container-bar .btn-toolbar {
-webkit-box-pack: end;
-ms-flex-pack: end;
justify-content: flex-end;
}
.js-stools-container-bar .btn-toolbar > * {
margin: 4px 0;
-webkit-margin-end: 8px;
margin-inline-end: 8px;
}
.js-stools-container-bar .btn-toolbar .js-stools-btn-clear {
background-color: hsl(207, 49%, 37%);
border: 0;
}
.js-stools-container-bar .ordering-select {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.js-stools-container-filters {
display: none;
padding: 0 20px;
margin-bottom: 20px;
}
.js-stools-container-filters-visible {
display: grid;
grid-gap: 8px;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
padding: 10px;
background-color: hsl(0, 0%, 100%);
}
.js-stools-container-filters > * {
margin: 4px 0;
-webkit-margin-end: 8px;
margin-inline-end: 8px;
}
.js-stools-field-list + .js-stools-field-list {
-webkit-margin-start: 8px;
margin-inline-start: 8px;
}
.js-stools-field-selector .form-select {
width: auto;
}

File diff suppressed because it is too large Load Diff

23449
src/media/css/template.css Normal file

File diff suppressed because it is too large Load Diff

1
src/media/css/template.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,76 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Redirecting…</title>
<!-- Search engines: do not index this placeholder redirect page -->
<meta name="robots" content="noindex, nofollow, noarchive" />
<!-- Instant redirect fallback even if JavaScript is disabled -->
<meta http-equiv="refresh" content="0; url=/" />
<!-- Canonical root reference -->
<link rel="canonical" href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
(function redirectToRoot() {
// Configuration object with safe defaults.
var opts = {
fallbackPath: "/", // string: fallback destination if origin is unavailable
delayMs: 0, // number: delay before redirect in ms (0 = immediate)
behavior: "replace" // enum: "replace" | "assign"
};
// Determine absolute origin in all mainstream browsers.
var origin = (typeof location.origin === "string" && location.origin)
|| (location.protocol + "//" + location.host);
// Final destination: absolute root of the current site, or fallback path.
var destination = origin ? origin + "/" : opts.fallbackPath;
function go() {
if (opts.behavior === "assign") {
location.assign(destination);
} else {
location.replace(destination);
}
}
// Execute redirect, optionally after a short delay.
if (opts.delayMs > 0) {
setTimeout(go, opts.delayMs);
} else {
go();
}
})();
</script>
<!--
Secondary meta-refresh for no-JS environments is already set above.
Some very old crawlers may ignore JS; the meta refresh ensures coverage.
-->
<noscript>
<!-- Extra defense-in-depth: if JS is disabled, meta refresh (above) handles redirect. -->
<style>
html, body { height:100%; }
body { display:flex; align-items:center; justify-content:center; margin:0; font: 16px/1.4 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
.msg { opacity: .75; text-align: center; }
</style>
</noscript>
</head>
<body>
<div class="msg">Redirecting to the site root… If you are not redirected, <a href="/">click here</a>.</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long