Add Sass build pipeline and production deploy script
- Move hand-authored CSS into src/scss/styles.scss, compiled to the tracked styles.css via `npm run build` (sass, no source maps). - Add package.json/package-lock.json with dev tooling: sass, and a `dev` script running php + sass --watch + browser-sync together. - Add scripts/build-dist.js (npm run dist): assembles an allowlisted, production-only copy of the site into dist/ (gitignored) for pushing to hosting — excludes node_modules, src/, package files, and the live db/fitz.sqlite while including config.php. - .gitignore: ignore node_modules/, styles.css.map, and dist/. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cd4c6c1969
commit
2145094e55
6 files changed
+4822
-106
No files matched your search
@@ -16,3 +16,10 @@ db/fitz.sqlite-shm
|
||||
.hintrc
|
||||
dev.sh
|
||||
.claude/
|
||||
|
||||
# Node development dependencies and Sass source maps
|
||||
node_modules/
|
||||
styles.css.map
|
||||
|
||||
# Generated deploy folder (npm run dist) — includes config.php, never commit
|
||||
dist/
|
||||
Generated
+2430
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "theoldfitz",
|
||||
"version": "1.0.0",
|
||||
"description": "The Old Fitz Public House website",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "concurrently --kill-others-on-fail \"npm:dev:php\" \"npm:dev:sass\" \"npm:dev:browser\"",
|
||||
"dev:php": "php -S localhost:8000",
|
||||
"dev:sass": "sass --watch --source-map src/scss/styles.scss:styles.css",
|
||||
"dev:browser": "browser-sync start --proxy http://localhost:8000 --files \"*.php,admin/**/*.php,inc/**/*.php,main.js,styles.css\" --no-open",
|
||||
"build": "sass --no-source-map src/scss/styles.scss:styles.css",
|
||||
"dist": "npm run build && node scripts/build-dist.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://gitea.home.daviddyer.me/david/the-old-fitz.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"devDependencies": {
|
||||
"browser-sync": "^3.0.4",
|
||||
"concurrently": "^10.0.5",
|
||||
"sass": "^1.103.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Assembles a clean, production-only copy of the site into dist/.
|
||||
*
|
||||
* This is an allowlist by design: only the files and folders listed below
|
||||
* are copied. Dev-only stuff (node_modules/, src/, package*.json, .git/,
|
||||
* .claude/, docker-compose.yaml, dev.sh, .hintrc, config.example.php, the
|
||||
* live db/fitz.sqlite, ...) never ends up in dist/ — including anything
|
||||
* added later, since it has to be added here explicitly first.
|
||||
*
|
||||
* Run with: npm run dist
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
const DIST = path.join(ROOT, 'dist');
|
||||
|
||||
const FILES = [
|
||||
'index.php',
|
||||
'menu.php',
|
||||
'main.js',
|
||||
'styles.css',
|
||||
'robots.txt',
|
||||
'config.php', // holds the live FB_PAGE_ACCESS_TOKEN — see README before sharing dist/ anywhere but the server
|
||||
];
|
||||
|
||||
const DIRS = ['admin', 'assets', 'inc'];
|
||||
|
||||
function copyDir(src, dest) {
|
||||
fs.cpSync(src, dest, {
|
||||
recursive: true,
|
||||
filter: (source) => path.basename(source) !== '.DS_Store',
|
||||
});
|
||||
}
|
||||
|
||||
// Fresh start every run so a file removed from the source tree doesn't
|
||||
// linger in dist/ from a previous build.
|
||||
fs.rmSync(DIST, { recursive: true, force: true });
|
||||
fs.mkdirSync(DIST, { recursive: true });
|
||||
|
||||
const missing = [];
|
||||
|
||||
for (const file of FILES) {
|
||||
const src = path.join(ROOT, file);
|
||||
if (!fs.existsSync(src)) {
|
||||
missing.push(file);
|
||||
continue;
|
||||
}
|
||||
fs.copyFileSync(src, path.join(DIST, file));
|
||||
}
|
||||
|
||||
for (const dir of DIRS) {
|
||||
const src = path.join(ROOT, dir);
|
||||
if (!fs.existsSync(src)) {
|
||||
missing.push(dir + '/');
|
||||
continue;
|
||||
}
|
||||
copyDir(src, path.join(DIST, dir));
|
||||
}
|
||||
|
||||
// db/ ships with just .htaccess (denies direct web access to the sqlite
|
||||
// file) — never the live fitz.sqlite itself. inc/db.php creates the
|
||||
// schema on first run if the file isn't there, so shipping the dev
|
||||
// database would just overwrite whatever is already live on the server.
|
||||
const dbHtaccess = path.join(ROOT, 'db', '.htaccess');
|
||||
if (fs.existsSync(dbHtaccess)) {
|
||||
fs.mkdirSync(path.join(DIST, 'db'), { recursive: true });
|
||||
fs.copyFileSync(dbHtaccess, path.join(DIST, 'db', '.htaccess'));
|
||||
} else {
|
||||
missing.push('db/.htaccess');
|
||||
}
|
||||
|
||||
if (missing.length) {
|
||||
console.warn('Warning: expected but not found, skipped:\n ' + missing.join('\n '));
|
||||
}
|
||||
|
||||
console.log(`Deploy folder built at ${path.relative(ROOT, DIST)}/`);
|
||||
File diff suppressed because it is too large.
Load diff
+99
-106
@@ -1,3 +1,4 @@
|
||||
@charset "UTF-8";
|
||||
:root {
|
||||
--ground: #171310;
|
||||
--ground-2: #0f0c0a;
|
||||
@@ -11,11 +12,9 @@
|
||||
--ink: #f1e8d8;
|
||||
--ink-muted: #a89a83;
|
||||
--rule: #42362590;
|
||||
|
||||
--font-serif: 'Fraunces', Georgia, 'Times New Roman', serif;
|
||||
--font-mono: 'IBM Plex Mono', ui-monospace, Menlo, monospace;
|
||||
--font-sans: 'Karla', ui-sans-serif, system-ui, sans-serif;
|
||||
|
||||
--danger-bg: rgba(180, 50, 40, 0.15);
|
||||
--danger-text: #ff9d9d;
|
||||
}
|
||||
@@ -33,7 +32,6 @@
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- wrap-aware separators (JS-toggled, see main.js) ----------
|
||||
Shared hook used by the announcement banner and hero tagline row: a
|
||||
"·" between two pieces of text that can independently wrap onto
|
||||
@@ -117,7 +115,7 @@
|
||||
border-radius: 0.125rem;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.85rem;
|
||||
transition: top .15s ease;
|
||||
transition: top 0.15s ease;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
@@ -340,7 +338,7 @@
|
||||
letter-spacing: 0.03em;
|
||||
color: var(--ink-muted);
|
||||
padding: 0.4rem 0.2rem;
|
||||
transition: color .15s ease;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
nav.links a:hover {
|
||||
@@ -387,11 +385,11 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-toggle[aria-expanded="true"] .icon-menu {
|
||||
.nav-toggle[aria-expanded=true] .icon-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-toggle[aria-expanded="true"] .icon-close {
|
||||
.nav-toggle[aria-expanded=true] .icon-close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -399,11 +397,9 @@
|
||||
.nav-toggle {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.nav-cta {
|
||||
display: none;
|
||||
}
|
||||
|
||||
nav.links {
|
||||
display: none;
|
||||
position: absolute;
|
||||
@@ -417,16 +413,13 @@
|
||||
border-bottom: 1px solid var(--rule);
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
nav.links.is-open {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
nav.links a {
|
||||
padding: 0.9rem 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- hero ---------- */
|
||||
.hero {
|
||||
position: relative;
|
||||
@@ -447,8 +440,7 @@
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
opacity: 0.6;
|
||||
background:
|
||||
linear-gradient(to bottom, rgba(0, 0, 0, 0.12), transparent 22%, transparent 78%, rgba(0, 0, 0, 0.18));
|
||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.12), transparent 22%, transparent 78%, rgba(0, 0, 0, 0.18));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -457,16 +449,14 @@
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
background-image: url('./assets/brick-texture.png');
|
||||
background-image: url("./assets/brick-texture.png");
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
.hero-scrim {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(15, 12, 10, 0.35) 0%, rgba(15, 12, 10, 0.2) 45%, rgba(15, 12, 10, 0.6) 100%),
|
||||
radial-gradient(ellipse 60% 48% at 50% 18%, rgba(201, 163, 92, 0.16), transparent 58%);
|
||||
background: linear-gradient(180deg, rgba(15, 12, 10, 0.35) 0%, rgba(15, 12, 10, 0.2) 45%, rgba(15, 12, 10, 0.6) 100%), radial-gradient(ellipse 60% 48% at 50% 18%, rgba(201, 163, 92, 0.16), transparent 58%);
|
||||
}
|
||||
|
||||
.hero-inner {
|
||||
@@ -545,7 +535,7 @@
|
||||
letter-spacing: 0.05em;
|
||||
text-decoration: none;
|
||||
border-radius: 0.125rem;
|
||||
transition: transform .15s ease, background .15s ease, border-color .15s ease;
|
||||
transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
@@ -688,7 +678,6 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* hours / visit band */
|
||||
.visit {
|
||||
background: var(--ground-2);
|
||||
@@ -805,7 +794,7 @@
|
||||
border-radius: 0.125rem;
|
||||
color: var(--ink-muted);
|
||||
text-decoration: none;
|
||||
transition: border-color .15s ease, color .15s ease;
|
||||
transition: border-color 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.social-row a:hover {
|
||||
@@ -823,7 +812,6 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* live music band */
|
||||
.music {
|
||||
background: linear-gradient(180deg, var(--green-deep), var(--green));
|
||||
@@ -895,20 +883,16 @@
|
||||
gap: 2.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.music-content {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.music .section-head {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.music .hero-ctas {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* menu band */
|
||||
.menu-band .container {
|
||||
max-width: 60rem;
|
||||
@@ -1021,12 +1005,11 @@
|
||||
gap: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* scroll reveal */
|
||||
.reveal {
|
||||
opacity: 0;
|
||||
transform: translateY(0.875rem);
|
||||
transition: opacity .6s ease, transform .6s ease;
|
||||
transition: opacity 0.6s ease, transform 0.6s ease;
|
||||
}
|
||||
|
||||
.reveal.is-visible {
|
||||
@@ -1041,7 +1024,6 @@
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- admin / management styles ---------- */
|
||||
.admin-login-body {
|
||||
min-height: 100vh;
|
||||
@@ -1118,7 +1100,7 @@
|
||||
border-radius: 0.125rem;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
transition: border-color .15s ease;
|
||||
transition: border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
@@ -1209,7 +1191,6 @@
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* two classes each, so these reliably outrank .admin-nav-links's and
|
||||
.admin-user's own base-rule gap regardless of source order */
|
||||
.admin-nav-inner .admin-nav-links,
|
||||
@@ -1218,7 +1199,6 @@
|
||||
gap: 0.5rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-layout {
|
||||
padding-block: 2.5rem 4rem;
|
||||
}
|
||||
@@ -1268,7 +1248,6 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
@@ -1297,7 +1276,7 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.checkbox-label input[type="checkbox"] {
|
||||
.checkbox-label input[type=checkbox] {
|
||||
width: 1.15rem;
|
||||
height: 1.15rem;
|
||||
accent-color: var(--gold);
|
||||
@@ -1344,7 +1323,7 @@
|
||||
-webkit-appearance: none;
|
||||
cursor: pointer;
|
||||
justify-content: center;
|
||||
transition: opacity .15s ease;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
button.status-badge:hover {
|
||||
@@ -1406,7 +1385,6 @@
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 0.75rem;
|
||||
@@ -1457,7 +1435,7 @@
|
||||
color: var(--ink-muted);
|
||||
padding: 0.35rem 0.65rem;
|
||||
border-radius: 0.125rem;
|
||||
transition: color .15s ease, background .15s ease;
|
||||
transition: color 0.15s ease, background 0.15s ease;
|
||||
}
|
||||
|
||||
.admin-nav-links a:hover {
|
||||
@@ -1592,9 +1570,7 @@
|
||||
.category-panel .panel-head {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-areas:
|
||||
"name actions"
|
||||
"desc actions";
|
||||
grid-template-areas: "name actions" "desc actions";
|
||||
align-items: center;
|
||||
column-gap: 0.75rem;
|
||||
}
|
||||
@@ -1688,39 +1664,90 @@
|
||||
}
|
||||
|
||||
.col-status,
|
||||
.item-row [data-label="Status"],
|
||||
.ann-row [data-label="Status"],
|
||||
.user-row [data-label="Status"] {
|
||||
.item-row [data-label=Status],
|
||||
.ann-row [data-label=Status],
|
||||
.user-row [data-label=Status] {
|
||||
grid-area: status;
|
||||
}
|
||||
|
||||
.col-actions,
|
||||
.item-row [data-label="Actions"],
|
||||
.ann-row [data-label="Actions"],
|
||||
.user-row [data-label="Actions"] {
|
||||
.item-row [data-label=Actions],
|
||||
.ann-row [data-label=Actions],
|
||||
.user-row [data-label=Actions] {
|
||||
grid-area: actions;
|
||||
}
|
||||
|
||||
.col-item { grid-area: item; }
|
||||
.col-price { grid-area: price; }
|
||||
.item-row [data-label="Item"] { grid-area: item; }
|
||||
.item-row [data-label="Price"] { grid-area: price; }
|
||||
.col-item {
|
||||
grid-area: item;
|
||||
}
|
||||
|
||||
.col-headline { grid-area: headline; }
|
||||
.col-type { grid-area: type; }
|
||||
.col-schedule { grid-area: schedule; }
|
||||
.col-placements { grid-area: placements; }
|
||||
.ann-row [data-label="Headline"] { grid-area: headline; }
|
||||
.ann-row [data-label="Type"] { grid-area: type; }
|
||||
.ann-row [data-label="Schedule"] { grid-area: schedule; }
|
||||
.ann-row [data-label="Placements"] { grid-area: placements; }
|
||||
.col-price {
|
||||
grid-area: price;
|
||||
}
|
||||
|
||||
.col-username { grid-area: username; }
|
||||
.col-role { grid-area: role; }
|
||||
.col-created { grid-area: created; }
|
||||
.user-row [data-label="Username"] { grid-area: username; }
|
||||
.user-row [data-label="Role"] { grid-area: role; }
|
||||
.user-row [data-label="Created"] { grid-area: created; }
|
||||
.item-row [data-label=Item] {
|
||||
grid-area: item;
|
||||
}
|
||||
|
||||
.item-row [data-label=Price] {
|
||||
grid-area: price;
|
||||
}
|
||||
|
||||
.col-headline {
|
||||
grid-area: headline;
|
||||
}
|
||||
|
||||
.col-type {
|
||||
grid-area: type;
|
||||
}
|
||||
|
||||
.col-schedule {
|
||||
grid-area: schedule;
|
||||
}
|
||||
|
||||
.col-placements {
|
||||
grid-area: placements;
|
||||
}
|
||||
|
||||
.ann-row [data-label=Headline] {
|
||||
grid-area: headline;
|
||||
}
|
||||
|
||||
.ann-row [data-label=Type] {
|
||||
grid-area: type;
|
||||
}
|
||||
|
||||
.ann-row [data-label=Schedule] {
|
||||
grid-area: schedule;
|
||||
}
|
||||
|
||||
.ann-row [data-label=Placements] {
|
||||
grid-area: placements;
|
||||
}
|
||||
|
||||
.col-username {
|
||||
grid-area: username;
|
||||
}
|
||||
|
||||
.col-role {
|
||||
grid-area: role;
|
||||
}
|
||||
|
||||
.col-created {
|
||||
grid-area: created;
|
||||
}
|
||||
|
||||
.user-row [data-label=Username] {
|
||||
grid-area: username;
|
||||
}
|
||||
|
||||
.user-row [data-label=Role] {
|
||||
grid-area: role;
|
||||
}
|
||||
|
||||
.user-row [data-label=Created] {
|
||||
grid-area: created;
|
||||
}
|
||||
|
||||
/* .item-rows being display:contents makes this a direct child of the
|
||||
.item-grid-wrap grid when a category is empty — span every column or
|
||||
@@ -1783,7 +1810,6 @@
|
||||
.user-grid-wrap {
|
||||
grid-template-columns: 1fr minmax(0, auto);
|
||||
}
|
||||
|
||||
/* Users' actions column gets a fixed cap instead of auto: "Change
|
||||
Password" is long enough that its max-content size (what auto would
|
||||
size the column to) is wider than this corner has room for, which
|
||||
@@ -1792,7 +1818,6 @@
|
||||
.user-grid-wrap {
|
||||
grid-template-columns: minmax(0, 1fr) 6rem;
|
||||
}
|
||||
|
||||
/* Every row's Actions cell holds one or two .action-stacks (move
|
||||
up/down, edit/delete, etc. — each stacked vertically, see
|
||||
.action-stack itself further up) side by side. Keeps those stacks
|
||||
@@ -1803,13 +1828,11 @@
|
||||
.user-row .row-actions {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.item-grid-head,
|
||||
.ann-grid-head,
|
||||
.user-grid-head {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item-row,
|
||||
.ann-row,
|
||||
.user-row {
|
||||
@@ -1819,14 +1842,12 @@
|
||||
padding: 0.9rem 1rem;
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
|
||||
.item-row:last-child,
|
||||
.ann-row:last-child,
|
||||
.user-row:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.item-row [data-label]::before,
|
||||
.ann-row [data-label]::before,
|
||||
.user-row [data-label]::before {
|
||||
@@ -1839,12 +1860,8 @@
|
||||
color: var(--gold);
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
grid-template-areas:
|
||||
"status actions"
|
||||
"item item"
|
||||
"price price";
|
||||
grid-template-areas: "status actions" "item item" "price price";
|
||||
/* Overrides the shared align-items: center above — on desktop that
|
||||
vertically centers Status against the taller Item cell in one wide
|
||||
row, which is fine, but here it also centers Status against the
|
||||
@@ -1852,26 +1869,14 @@
|
||||
keeping both flush with the card's top edge. */
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.ann-row {
|
||||
grid-template-areas:
|
||||
"status actions"
|
||||
"headline headline"
|
||||
"type type"
|
||||
"schedule schedule"
|
||||
"placements placements";
|
||||
grid-template-areas: "status actions" "headline headline" "type type" "schedule schedule" "placements placements";
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.user-row {
|
||||
grid-template-areas:
|
||||
"status actions"
|
||||
"username username"
|
||||
"role role"
|
||||
"created created";
|
||||
grid-template-areas: "status actions" "username username" "role role" "created created";
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* Stretches Actions' whole flex chain out to the fixed 6rem column
|
||||
above (each is shrink-wrapped by default), then lets "Change
|
||||
Password" — long enough on its own to blow out this corner next to a
|
||||
@@ -1883,21 +1888,15 @@
|
||||
.user-row .row-actions .btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-row .btn-change-password {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.category-panel .panel-head {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas:
|
||||
"name"
|
||||
"desc"
|
||||
"actions";
|
||||
grid-template-areas: "name" "desc" "actions";
|
||||
row-gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- admin modal dialogs ---------- */
|
||||
.admin-modal-backdrop {
|
||||
position: fixed;
|
||||
@@ -1911,7 +1910,7 @@
|
||||
padding: 1.5rem;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity .2s ease;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.admin-modal-backdrop.is-open {
|
||||
@@ -1930,7 +1929,7 @@
|
||||
padding: 2rem;
|
||||
box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.6);
|
||||
transform: translateY(0.75rem);
|
||||
transition: transform .2s ease;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.admin-modal-backdrop.is-open .admin-modal {
|
||||
@@ -1961,7 +1960,7 @@
|
||||
padding: 0.25rem;
|
||||
line-height: 1;
|
||||
text-decoration: none;
|
||||
transition: color .15s ease;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
@@ -2002,7 +2001,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0.125rem;
|
||||
transition: color .15s ease;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.password-toggle-btn:hover {
|
||||
@@ -2089,11 +2088,9 @@
|
||||
.hours-grid-wrap {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hours-grid-head {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hours-day-row {
|
||||
grid-template-columns: 1fr;
|
||||
row-gap: 0.5rem;
|
||||
@@ -2102,11 +2099,9 @@
|
||||
padding: 0.9rem 1rem;
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
|
||||
.hours-day-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.hours-day-row [data-label]::before {
|
||||
content: attr(data-label);
|
||||
display: block;
|
||||
@@ -2117,12 +2112,10 @@
|
||||
color: var(--gold);
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.hours-day-row .form-control {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Live preview panel: mimics the public site's Visit card and footer
|
||||
mini-summary without depending on their .card/footer ancestor scoping
|
||||
(this lives inside an admin .panel, which already shares that same
|
||||
|
||||
Reference in new issue
Block a user