website: M3 part A - the controller's shell, and the home page inside it
gates / gates (push) Successful in 6m58s
gates / gates (push) Successful in 6m58s
The direction the operator chose: the controller's FRAME around the website's own
content. Staged at /preview/m3/, noindex, nothing live.
website/assets/shell.css - 117 rules COPIED VERBATIM from felhom-controller
style.css @ dcd89364a4 (sidebar, mobile top bar, off-canvas drawer, and the
component atoms the restyled pages use: btn, alert, app-info-card, launch-*,
stack-detail-card, form-*). Exactly ONE rule is not verbatim and says so:
body.shell { display:flex; min-height:100vh }, which lives in the controller's
base rather than in a component, scoped to .shell so other pages are untouched.
The generator NAMES every rule it copies and REFUSES to write the file if one has
disappeared upstream. That is not ceremony: it already caught two things this
session. It refused because .sidebar::-webkit-scrollbar does not exist (only the
-track override does), and because prefers-reduced-motion is split across FIVE
separate blocks in the controller - reading only the first would have silently
lost four rules. The M1 round lost a rule exactly this way.
The bare `body { flex-direction: column }` that broke M1's phone layout is copied
this time, by name, as are body.nav-open and the no-js/js pair.
Load order is deliberate: shell.css AFTER site.css. Thirteen selectors exist in
both files with different meanings (.nav-links, .page-header, .lang-globe*, .ico)
- a horizontal site nav there, a vertical sidebar here. Later wins, and a page
that does not load shell.css is completely unaffected.
website/preview/m3/index.html - the home page in the shell. Content is /preview/'s
cleaned text; body carries `shell page-index` so the existing .page-index content
rules (caps, flow, vs, band, who-mini) are reused rather than duplicated. Six
sections, left-aligned headers, the controller's cards. Head tags (title, meta
description, canonical, hreflang) are already the FINAL values, so the switch in
part D needs no head edit.
Four changes from the operator's mockup, each with its reason in the generator:
1. the active item follows the page (the mockups show Inditopult active on all)
2. Teszteles is ALSO a primary button at the top of the lower group - it is the
one action we want and the mockup buries it at the bottom
3. the Alkalmazasok categories are anchors on /alkalmazasok: real URLs, no
JS-only state
4. ADDED GYIK. It is in today's nav; dropping it silently would take a page out
of navigation, which is not a change a restyle gets to make.
scripts/site_gates.py - gate 3 extended rather than duplicated, as asked: a SHELL
set whose pages must carry an IDENTICAL <nav class="sidebar"> after the active
marker is normalised. RED-PROOFED: a one-character change to one menu label on a
second shell page convicts. It also prints "DIFFER" rather than a reassuring
"identical" count when it fails - a false reassurance printed beside a conviction
is the exact defect this repo files rows about.
documentation/design/design-system.md - new "Shell" section: what is shared (tokens
+ shell + atoms), what each side owns, how a change flows (controller first, the
website's copy the same week), and that the cross-repo gate is deliberately NOT
built yet.
This commit is contained in:
@@ -0,0 +1,740 @@
|
||||
/* =============================================================================
|
||||
shell.css - the controller's frame, around the website's own content.
|
||||
|
||||
COPIED, NOT WRITTEN. Source: felhom-controller
|
||||
controller/internal/web/templates/style.css @ dcd89364a4
|
||||
(the markup it styles is that repo's templates/layout.html).
|
||||
|
||||
KEEP IN STEP WITH THE CONTROLLER - see documentation/design/design-system.md
|
||||
"Shell". A change flows controller first, then this copy.
|
||||
|
||||
Loaded AFTER site.css on purpose. Thirteen selectors exist in both files
|
||||
(.nav-links, .nav-links a, .page-header, .lang-globe*, .ico, .ico-sm) with
|
||||
different meanings - a horizontal site nav there, a vertical sidebar here.
|
||||
Later wins, so the shell's meaning is the one that applies on a shell page.
|
||||
A page that does not load this file is completely unaffected.
|
||||
|
||||
Rules copied VERBATIM; only this header is new. The generator refuses to
|
||||
write the file if any rule named below has disappeared upstream, so an
|
||||
incomplete copy fails loudly instead of rendering wrong (the lesson in
|
||||
documentation/audits/mockups-2026-10-11/SHARED-DESIGN.md section 2).
|
||||
============================================================================= */
|
||||
|
||||
/* ---------- ADAPTED (the only non-verbatim rules in this file) ----------
|
||||
The controller's BASE gives body `display:flex; min-height:100vh` - that is what puts
|
||||
the sidebar beside the content. site.css has no such rule, so it is restated here,
|
||||
SCOPED to .shell so a page without the shell is untouched. For the same reason the two
|
||||
bare `body` rules in the phone block below are emitted as `body.shell`.
|
||||
Everything else in this file is verbatim. */
|
||||
body.shell { display: flex; min-height: 100vh; }
|
||||
|
||||
/* ---------- shell, desktop ---------- */
|
||||
|
||||
.ico {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
vertical-align: -0.18em;
|
||||
}
|
||||
|
||||
.ico-sm {
|
||||
width: 14px; height: 14px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 240px;
|
||||
background: var(--bg-2);
|
||||
color: var(--text-1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-track {
|
||||
background: var(--bg-2);
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.sidebar-logo {
|
||||
width: 140px;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: 0 auto 0.25rem;
|
||||
}
|
||||
|
||||
.sidebar-bottom {
|
||||
margin-top: auto;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid var(--line);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
list-style: none;
|
||||
padding: 1rem 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
padding: .75rem 1.5rem;
|
||||
color: var(--text-2);
|
||||
text-decoration: none;
|
||||
font-size: .95rem;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: var(--blue-bright);
|
||||
background: var(--blue-dim);
|
||||
}
|
||||
|
||||
.nav-links a.active {
|
||||
color: var(--blue-bright);
|
||||
background: var(--blue-dim);
|
||||
border-left: 3px solid var(--blue);
|
||||
}
|
||||
|
||||
.nav-links-sub {
|
||||
padding: 0 0 .5rem;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.nav-links-sub a {
|
||||
padding: .5rem 1.5rem .5rem 1.75rem;
|
||||
font-size: .88rem;
|
||||
}
|
||||
|
||||
.nav-links-nested {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav-links-nested a {
|
||||
padding: .4rem 1.5rem .4rem 3.1rem;
|
||||
font-size: .85rem;
|
||||
}
|
||||
|
||||
.nav-links-nested a.active {
|
||||
border-left: 3px solid var(--blue);
|
||||
}
|
||||
|
||||
.nav-group-label {
|
||||
padding: .75rem 1.5rem .25rem;
|
||||
font-size: .68rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-3);
|
||||
}
|
||||
|
||||
.nav-group {
|
||||
display: grid;
|
||||
grid-template-rows: auto 0fr;
|
||||
transition: grid-template-rows .18s ease;
|
||||
}
|
||||
|
||||
.nav-group.is-open {
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
.nav-group > .nav-links-nested {
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.nav-group-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
width: 100%;
|
||||
padding: .75rem 1.5rem;
|
||||
background: none;
|
||||
border: none;
|
||||
border-left: 3px solid transparent;
|
||||
color: var(--text-2);
|
||||
font-family: inherit;
|
||||
font-size: .95rem;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease, background 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-group-toggle:hover {
|
||||
color: var(--blue-bright);
|
||||
background: var(--blue-dim);
|
||||
}
|
||||
|
||||
.nav-group-toggle.active {
|
||||
color: var(--blue-bright);
|
||||
background: var(--blue-dim);
|
||||
border-left-color: var(--blue);
|
||||
}
|
||||
|
||||
.nav-group-toggle:focus-visible {
|
||||
outline: 2px solid var(--blue-bright);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.nav-chevron {
|
||||
margin-left: auto;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
color: var(--text-3);
|
||||
transition: transform .18s ease;
|
||||
}
|
||||
|
||||
.nav-group.is-open .nav-chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.mobile-topbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-backdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-burger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .375rem;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-2);
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-burger:hover {
|
||||
color: var(--blue-bright);
|
||||
}
|
||||
|
||||
.nav-burger:focus-visible {
|
||||
outline: 2px solid var(--blue-bright);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.nav-burger .ico {
|
||||
width: 24px; height: 24px;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 240px;
|
||||
padding: 2rem;
|
||||
flex: 1;
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.version {
|
||||
color: var(--text-3);
|
||||
}
|
||||
|
||||
.logout-link {
|
||||
color: var(--text-3); text-decoration: none; transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.logout-link:hover {
|
||||
color: var(--blue-bright);
|
||||
}
|
||||
|
||||
.lang-globe {
|
||||
position: relative; margin: 0;
|
||||
}
|
||||
|
||||
.lang-globe-btn {
|
||||
list-style: none; display: inline-flex; align-items: center; color: var(--text-3); cursor: pointer; padding: .15rem; border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.lang-globe-btn::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lang-globe-btn:hover, .lang-globe[open] .lang-globe-btn {
|
||||
color: var(--blue-bright);
|
||||
}
|
||||
|
||||
.lang-globe-menu {
|
||||
position: absolute; bottom: calc(100% + .35rem); left: 50%; transform: translateX(-50%); margin: 0; padding: .25rem; list-style: none; min-width: 7.5rem; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); z-index: 20;
|
||||
}
|
||||
|
||||
.lang-globe-menu li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.lang-globe-item {
|
||||
display: block; width: 100%; text-align: left; background: none; border: none; color: var(--text-2); font: inherit; font-size: .8rem; padding: .3rem .5rem; border-radius: var(--radius); cursor: pointer; white-space: nowrap;
|
||||
}
|
||||
|
||||
.lang-globe-item:hover {
|
||||
color: var(--blue-bright);
|
||||
}
|
||||
|
||||
.lang-globe-item.current {
|
||||
color: var(--text-1); font-weight: 600;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.page-header h2 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-1);
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .3rem;
|
||||
padding: .5rem 1rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
font-size: .85rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
||||
text-decoration: none;
|
||||
color: var(--text-1);
|
||||
font-family: inherit;
|
||||
background: var(--bg-2);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
opacity: .5; cursor: not-allowed; transform: none;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: .3rem .6rem; font-size: .8rem;
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
padding: .65rem 1.5rem; font-size: 1rem;
|
||||
}
|
||||
|
||||
.btn-full {
|
||||
width: 100%; justify-content: center;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--blue);
|
||||
border-color: var(--blue);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--blue-bright); border-color: var(--blue-bright);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
border: 1px solid var(--line);
|
||||
color: var(--text-2);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
border-color: var(--blue);
|
||||
color: var(--blue-bright);
|
||||
background: var(--blue-dim);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: transparent;
|
||||
border: 1px solid var(--crit);
|
||||
color: var(--crit);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: var(--crit-dim);
|
||||
}
|
||||
|
||||
.app-info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.app-info-card {
|
||||
background: var(--bg-1);
|
||||
border-radius: var(--radius);
|
||||
padding: 1.25rem;
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.app-info-card h3 {
|
||||
margin: 0 0 .75rem 0;
|
||||
font-size: .95rem;
|
||||
color: var(--text-1);
|
||||
}
|
||||
|
||||
.app-info-list {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
color: var(--text-2);
|
||||
font-size: .9rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.app-info-link {
|
||||
color: var(--blue-bright);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.app-info-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.alerts-container {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.alert-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: var(--radius);
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.alert-banner-info {
|
||||
background: var(--blue-dim);
|
||||
border-color: var(--blue-dim);
|
||||
color: var(--blue-bright);
|
||||
}
|
||||
|
||||
.alert-banner-warning {
|
||||
background: var(--warn-dim);
|
||||
border-color: var(--warn-dim);
|
||||
color: var(--warn);
|
||||
}
|
||||
|
||||
.alert-banner-error {
|
||||
background: var(--crit-dim);
|
||||
border-color: var(--crit-dim);
|
||||
color: var(--crit);
|
||||
}
|
||||
|
||||
.alert-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.alert-message {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.alert-link {
|
||||
margin-left: auto; white-space: nowrap; color: inherit; text-decoration: none;
|
||||
}
|
||||
|
||||
.alert-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.domain-badge {
|
||||
border: 1px solid var(--line);
|
||||
color: var(--text-2);
|
||||
padding: .2rem .6rem;
|
||||
border-radius: var(--radius);
|
||||
font-size: .8rem;
|
||||
font-weight: 500;
|
||||
font-family: var(--font-data);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center; padding: 3rem; color: var(--text-3);
|
||||
}
|
||||
|
||||
.empty-state-link {
|
||||
color: var(--blue-bright);
|
||||
}
|
||||
|
||||
.form-hint {
|
||||
font-size: .85rem;
|
||||
color: var(--text-3);
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--text-3);
|
||||
}
|
||||
|
||||
.launch-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
|
||||
gap: 1.25rem;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.launch-cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
text-decoration: none;
|
||||
color: var(--text-1);
|
||||
}
|
||||
|
||||
.launch-tile {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--line);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
transition: transform .12s ease, border-color .12s ease;
|
||||
}
|
||||
|
||||
.launch-cell:hover .launch-tile {
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
.launch-mono {
|
||||
display: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: var(--font-ui);
|
||||
font-size: 2.4rem;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.launch-logo {
|
||||
position: relative;
|
||||
width: 58%;
|
||||
height: 58%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.launch-name {
|
||||
max-width: 100%;
|
||||
font-size: .85rem;
|
||||
color: var(--text-1);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.stack-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.stack-detail-card {
|
||||
background: var(--bg-1);
|
||||
border-radius: var(--radius);
|
||||
padding: 1.25rem;
|
||||
border: 1px solid var(--line);
|
||||
transition: border-color 0.3s ease, transform 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.stack-detail-card:hover {
|
||||
border-color: var(--blue);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.stack-title-text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.stack-title-text h3 {
|
||||
margin-bottom: .25rem; overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.stack-detail-desc {
|
||||
color: var(--text-2);
|
||||
font-size: .85rem;
|
||||
margin-bottom: .75rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block; font-size: .85rem; font-weight: 500; margin-bottom: .4rem; color: var(--text-1);
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: .55rem .75rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
font-size: .9rem;
|
||||
background: var(--bg-2);
|
||||
color: var(--text-1);
|
||||
font-family: inherit;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
outline: none;
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
.form-control:disabled {
|
||||
background: var(--bg-0);
|
||||
color: var(--text-3);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
margin-bottom: .75rem;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: .75rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .5rem;
|
||||
margin-top: .25rem;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: var(--crit);
|
||||
}
|
||||
|
||||
|
||||
/* ---------- shell, phone: top bar + off-canvas drawer ----------
|
||||
`body` and `body.nav-open` are element-level rules the components depend on.
|
||||
Dropping them is what broke the M1 phone layout. They are copied here on purpose. */
|
||||
@media (max-width: 768px) {
|
||||
|
||||
.mobile-topbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 800;
|
||||
background: var(--bg-2);
|
||||
border-bottom: 1px solid var(--line);
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
|
||||
.mobile-topbar-logo img {
|
||||
height: 36px; width: auto; display: block;
|
||||
}
|
||||
|
||||
.js .sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
width: min(280px, 85vw);
|
||||
transform: translateX(-100%);
|
||||
transition: transform .2s ease;
|
||||
z-index: 950;
|
||||
border-right: 1px solid var(--line);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.js .sidebar.is-open {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.js .nav-backdrop:not([hidden]) {
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
z-index: 900;
|
||||
}
|
||||
|
||||
body.shell.nav-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.no-js .sidebar {
|
||||
position: static;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.no-js .nav-burger {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 0; padding: 1rem;
|
||||
}
|
||||
|
||||
body.shell {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-wrap: wrap; row-gap: .6rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---------- shell, reduced motion ---------- */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
.nav-group {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.nav-chevron {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.js .sidebar {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@@ -2376,3 +2376,54 @@ footer a:hover, footer a:focus-visible { text-decoration: underline; }
|
||||
.page-index .who-mini p { text-align: center; }
|
||||
}
|
||||
|
||||
|
||||
/* ================= M3 shell pages - 2026-10-11 =================
|
||||
Additions only, all new class names. These are the WEBSITE's own additions to the
|
||||
controller's shell (assets/shell.css, which stays a pure copy): the wordmark under
|
||||
the sidebar logo, the tester button in the sidebar, the hero row, and the sample
|
||||
badge. Nothing here exists in the controller, so nothing here has to keep in step
|
||||
with it. See documentation/design/design-system.md "Shell". */
|
||||
|
||||
/* --- the website's own additions to the sidebar --- */
|
||||
.sidebar-logo-link { display: flex; flex-direction: column; align-items: center; gap: 8px; }
|
||||
.sidebar-word { height: 16px; width: auto; display: block; }
|
||||
.sidebar-cta { width: 100%; justify-content: center; margin-bottom: 1rem; }
|
||||
|
||||
/* --- every invented value on a page wears this --- */
|
||||
.sample {
|
||||
font-family: var(--font-data); font-size: .68rem; text-transform: uppercase;
|
||||
letter-spacing: .04em; color: var(--warn);
|
||||
border: 1px solid var(--warn); background: var(--warn-dim);
|
||||
padding: .05rem .3rem; border-radius: var(--radius); white-space: nowrap;
|
||||
}
|
||||
|
||||
/* --- section rhythm inside the shell's content column --- */
|
||||
.shell-section { margin-bottom: 3.5rem; }
|
||||
.shell-section:last-child { margin-bottom: 1rem; }
|
||||
.shell .sec-head { max-width: 46rem; margin-bottom: 1.75rem; }
|
||||
.shell .sec-head h2 { font-size: clamp(1.4rem, 2.6vw, 1.9rem); font-weight: 700; letter-spacing: -.02em; margin-bottom: .4rem; }
|
||||
.shell .sec-head p { color: var(--text-2); font-size: 1rem; }
|
||||
|
||||
/* --- the hero row: copy on the left, the dashboard window on the right --- */
|
||||
.hero-row { display: grid; grid-template-columns: 1fr 1.1fr; gap: 2.5rem; align-items: center; margin-bottom: 3.5rem; }
|
||||
.hero-copy h1 { font-size: clamp(1.8rem, 3.4vw, 2.6rem); font-weight: 700; line-height: 1.15; letter-spacing: -.03em; margin-bottom: .75rem; }
|
||||
.hero-copy p { color: var(--text-2); font-size: 1.05rem; margin-bottom: 1.5rem; max-width: 34ch; }
|
||||
.hero-logo { display: flex; justify-content: center; }
|
||||
.hero-logo img { max-width: 340px; width: 100%; height: auto; }
|
||||
.hero-window { border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-1); overflow: hidden; }
|
||||
.hero-window-bar { display: flex; align-items: center; gap: .4rem; padding: .55rem .8rem; background: var(--bg-2); border-bottom: 1px solid var(--line); }
|
||||
.hw-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line); display: inline-block; }
|
||||
.hero-window-title { margin-left: .7rem; font-size: .78rem; color: var(--text-3); display: inline-flex; align-items: center; gap: .5rem; }
|
||||
.hero-window-body { padding: 1.1rem; }
|
||||
.hero-window-lede { font-size: .88rem; color: var(--text-2); margin-bottom: .9rem; }
|
||||
.launch-grid--mini { grid-template-columns: repeat(4, 1fr); gap: .9rem; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.hero-row { grid-template-columns: 1fr; gap: 1.75rem; }
|
||||
.hero-copy p { max-width: none; }
|
||||
.launch-grid--mini { grid-template-columns: repeat(4, 1fr); }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.launch-grid--mini { grid-template-columns: repeat(3, 1fr); }
|
||||
.shell-section { margin-bottom: 2.5rem; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user