Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/assets/scss/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
.nav-links a {
text-decoration: none;
color: var(--color-text-muted);
font-family: var(--font-mono);
font-size: 0.95rem;
font-weight: 500;
transition: color 0.3s ease;
Expand Down
61 changes: 49 additions & 12 deletions app/assets/scss/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,33 @@
@use 'utilities';

:root {
--color-bg: #050816;
--color-bg-secondary: #0d111d;
--color-terminal: rgba(13, 17, 23, 0.85);
--color-text: #fff;
--color-text-muted: #9ca3af;
--color-accent: #00f5ff;
--color-error: #f85149;
--color-success: #3fb950;
--color-glass-border: rgba(0, 245, 255, 0.2);
// Canonical MCTL design tokens, vendored from @mctlhq/tokens (the same
// dependency-free pattern mctl-telegram and mctl-instruments use). Keep the
// existing --color-* variable names so consumers don't all need rewiring;
// only the values change — from the old #050816/#00f5ff fork to the
// canonical ink/cyan palette and the hairline (not glow) aesthetic.
--color-bg: #0a0b0d; // ink
--color-bg-secondary: #0f1114; // ink2 / elevated
--color-card: #15181d; // ink3 / card
--color-terminal: rgba(21, 24, 29, 0.85);
--color-text: #e6e7e9; // fg
--color-text-muted: #a4a8ae; // fg2
--color-text-subtle: #6b7079; // fg3
--color-accent: #00e5ff; // cyan
--color-accent-highlight: #7df2ff;
--color-error: #ff6b6b; // status bad
--color-success: #7cf2a4; // status ok
--color-warn: #f5a524; // status warn
--color-line: #1f242b; // hairline
--color-line-strong: #2a313a;
// Borders are neutral hairlines, not cyan, in the canonical language.
--color-glass-border: var(--color-line);
--color-accent-soft: rgba(0, 229, 255, 0.1);
// Elevation is shadow-light; hover lifts on a hairline + a quiet drop, no glow.
--shadow-card-hover: 0 16px 48px rgba(0, 0, 0, 0.48);

--font-display: 'Geist', system-ui, -apple-system, sans-serif;
--font-editorial: 'Instrument Serif', Georgia, serif;
--font-mono: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
--container-width: 1400px;
--container-width-md: 1200px;
Expand All @@ -32,8 +50,9 @@ html {
}

body {
position: relative;
font-size: 14px;
font-family: var(--font-mono);
font-family: var(--font-display);
background-color: var(--color-bg);
color: var(--color-text);
line-height: 1.6;
Expand All @@ -46,6 +65,24 @@ body {
}
}

// Ambient background: a faint neutral blueprint grid — engineering texture,
// not a glow. Recoloured from cyan to a hairline tone to match the design
// system's restraint; fixed so it stays put while content scrolls.
body::before {
content: '';
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image:
linear-gradient(rgba(255, 255, 255, 0.018) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.018) 1px, transparent 1px);
background-size: 56px 56px, 56px 56px;
// Fade the grid out toward the bottom so it reads as atmosphere, not a table.
mask-image: linear-gradient(180deg, #000 0%, #000 55%, transparent 100%);
-webkit-mask-image: linear-gradient(180deg, #000 0%, #000 55%, transparent 100%);
}

a {
color: inherit;
text-decoration: none;
Expand All @@ -65,7 +102,7 @@ h1, h2, h3, h4, h5, h6 {

h1 {
font-size: 32px;
font-weight: 800;
font-weight: 700;
text-align: center;
color: #fff;
margin-bottom: 1.5rem;
Expand All @@ -83,7 +120,7 @@ h1 {

h2 {
font-size: 28px;
font-weight: 800;
font-weight: 700;

@media (min-width: 768px) {
font-size: 36px;
Expand Down
226 changes: 210 additions & 16 deletions app/components/main/HeroBlock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,54 @@ const { t } = useI18n()
<section class="hero-block">
<div class="hero-block__glow"></div>
<BaseContainer size="md">
<h1>
{{ t('hero.title') }}
</h1>
<p class="hero-block__description" v-html="t('hero.subtitle')" />
<BaseButton
size="lg"
@click="$router.push({ hash: '#request-access' })"
>
{{ t('hero.cta') }}
</BaseButton>
<div class="hero-block__intro">
<span class="hero-block__badge">
<span class="hero-block__badge-dot"></span>
{{ t('hero.badge') }}
</span>
<h1>
{{ t('hero.title') }}
</h1>
<p class="hero-block__description" v-html="t('hero.subtitle')" />
<div class="hero-block__actions">
<BaseButton
size="lg"
@click="$router.push({ hash: '#request-access' })"
>
{{ t('hero.cta') }}
</BaseButton>
<a class="hero-block__secondary" href="/docs">
{{ t('hero.cta_secondary') }}
<span aria-hidden="true">&#8594;</span>
</a>
</div>
</div>

<div class="hero-terminal" aria-hidden="true">
<div class="hero-terminal__bar">
<span class="hero-terminal__dot hero-terminal__dot--red"></span>
<span class="hero-terminal__dot hero-terminal__dot--amber"></span>
<span class="hero-terminal__dot hero-terminal__dot--green"></span>
<span class="hero-terminal__title">mctl &mdash; deploy</span>
</div>
<div class="hero-terminal__body">
<p class="hero-terminal__line">
<span class="hero-terminal__prompt">$</span> git push origin main
</p>
<p class="hero-terminal__line hero-terminal__line--muted">
&rarr; building image &middot; running tests &middot; generating manifests
</p>
<p class="hero-terminal__line hero-terminal__line--ok">
&check; deployed to <span class="hero-terminal__accent">my-team</span> namespace
</p>
<p class="hero-terminal__line">
<span class="hero-terminal__prompt">$</span> mctl ask <span class="hero-terminal__str">"roll my-app back to v1.4.2"</span>
</p>
<p class="hero-terminal__line hero-terminal__line--ok">
&check; rollback live at <span class="hero-terminal__accent">app.mctl.ai</span><span class="hero-terminal__cursor"></span>
</p>
</div>
</div>
</BaseContainer>
</section>
</template>
Expand All @@ -24,7 +62,7 @@ const { t } = useI18n()
.hero-block {
position: relative;
padding: 60px 0;
height: calc(100vh - var(--header-height));
min-height: calc(100vh - var(--header-height));
display: flex;
align-items: center;
justify-content: center;
Expand All @@ -36,9 +74,40 @@ const { t } = useI18n()
font-size: clamp(2.5rem, 4.5vw, 4.25rem);
}

&__intro {
position: relative;
z-index: 1;
}

&__badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.75rem;
padding: 0.4rem 0.9rem;

font-size: 0.75rem;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 — badge renders in Geist; design intent says eyebrows should use mono

The PR description states "JetBrains Mono retained for chrome (nav, eyebrows, code, terminal)" and the BaseSection overline already has font-family: var(--font-mono) added in this PR. The hero-block__badge is the same eyebrow-style element; without an override it inherits Geist from body.

Suggested change
font-size: 0.75rem;
font-size: 0.75rem;
font-family: var(--font-mono);
letter-spacing: 1px;

letter-spacing: 1px;
text-transform: uppercase;
color: var(--color-accent);

background: var(--color-accent-soft);
border: 1px solid var(--color-glass-border);
border-radius: 999px;
}

&__badge-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--color-accent);
box-shadow: 0 0 8px var(--color-accent);
animation: heroPulse 2s ease-in-out infinite;
}

&__description {
max-width: 900px;
margin: 0 auto 48px;
margin: 0 auto 40px;
text-align: center;
font-size: 18px;
color: var(--color-text-muted);
Expand All @@ -49,16 +118,141 @@ const { t } = useI18n()
}
}

&__actions {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 1.25rem;
}

&__secondary {
display: inline-flex;
align-items: center;
gap: 0.5rem;

color: var(--color-text-muted);
font-weight: 500;
transition: color 0.25s ease, gap 0.25s ease;

span {
transition: transform 0.25s ease;
}

&:hover {
color: var(--color-accent);

span {
transform: translateX(4px);
}
}
}

&__glow {
position: absolute;
top: 20%;
top: 18%;
left: 50%;
transform: translate(-50%, -50%);
width: 60vw;
height: 60vw;
background: radial-gradient(circle, rgba(0, 245, 255, 0.1) 0%, transparent 70%);
width: 70vw;
height: 70vw;
max-width: 900px;
max-height: 900px;
// Quiet ambient wash — restrained per the design system's hairline language.
background: radial-gradient(circle, rgba(0, 229, 255, 0.05) 0%, transparent 65%);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 — glow uses a raw rgba value that diverges from the token set

rgba(0, 229, 255, 0.05) is half the opacity of --color-accent-soft (rgba(0, 229, 255, 0.1)). If the dimmer value is intentional, introduce a named token (e.g. --color-accent-dim) in base.scss; otherwise reuse the existing one.

Suggested change
background: radial-gradient(circle, rgba(0, 229, 255, 0.05) 0%, transparent 65%);
background: radial-gradient(circle, var(--color-accent-soft) 0%, transparent 65%);

z-index: 0;
pointer-events: none;
}
}

// Terminal mockup — gives the hero a concrete focal point and shows
// the core "push / ask AI / live" loop in the product's own voice.
.hero-terminal {
position: relative;
z-index: 1;
max-width: 640px;
margin: 4rem auto 0;

text-align: left;
background: var(--color-terminal);
border: 1px solid var(--color-glass-border);
border-radius: 12px;
overflow: hidden;
backdrop-filter: blur(8px);
box-shadow: var(--shadow-card-hover);

&__bar {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
background: rgba(255, 255, 255, 0.03);
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

&__dot {
width: 11px;
height: 11px;
border-radius: 50%;

&--red { background: #ff5f56; }
&--amber { background: #ffbd2e; }
&--green { background: #27c93f; }
}

&__title {
margin-left: auto;
font-size: 0.75rem;
color: var(--color-text-muted);
letter-spacing: 0.5px;
}

&__body {
padding: 1.5rem 1.5rem 1.75rem;
// Body inherits the page's Geist now; force mono so the terminal reads
// as a terminal.
font-family: var(--font-mono);
font-size: 0.85rem;
line-height: 1.9;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 — terminal content will render in Geist, not monospace

base.scss in this same PR switches body { font-family } from var(--font-mono) to var(--font-display). .hero-terminal__body inherits that change and will now render all terminal lines in Geist — a proportional sans-serif — which breaks the visual metaphor entirely.

Add an explicit override:

Suggested change
line-height: 1.9;
padding: 1.5rem 1.5rem 1.75rem;
font-size: 0.85rem;
font-family: var(--font-mono);
line-height: 1.9;

Fix this →


@media (max-width: 480px) {
font-size: 0.72rem;
}
}

&__line {
margin: 0;

&--muted { color: var(--color-text-muted); }
&--ok { color: var(--color-success); }
}

&__prompt { color: var(--color-accent); }
&__accent { color: var(--color-accent); }
&__str { color: #ffbd2e; }

&__cursor {
display: inline-block;
width: 8px;
height: 1em;
margin-left: 4px;
vertical-align: text-bottom;
background: var(--color-accent);
animation: heroBlink 1.1s step-end infinite;
}
}

@keyframes heroPulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.4; transform: scale(0.85); }
}

@keyframes heroBlink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
.hero-block__badge-dot,
.hero-terminal__cursor { animation: none; }
}
</style>
Loading
Loading