Skip to content

feat: align mctl-web with the MCTL design system - #17

Merged
mashkovd merged 3 commits into
mainfrom
feat/visual-polish
May 29, 2026
Merged

mashkovd merged 3 commits into
mainfrom
feat/visual-polish

Conversation

@mashkovd

Copy link
Copy Markdown
Member

Summary

Re-skins mctl-web onto the canonical MCTL design tokens so it stops diverging from the design system (it was using a #050816/#00f5ff fork with all-monospace type). Uses the dependency-free token-vendoring pattern that mctl-telegram and mctl-instruments already follow.

Changes

  • Palette: ink #0a0b0d + cyan #00e5ff (canonical), neutral hairline borders instead of cyan glass borders
  • Type: Geist for display/body, Instrument Serif available for ledes, JetBrains Mono retained for chrome (nav, eyebrows, code, terminal)
  • Aesthetic: replace cyan glows/sheens with the system's restrained hairline language; recolour the ambient grid to a neutral blueprint tone
  • Load Geist + Instrument Serif alongside JetBrains Mono

Earlier commit (also in this PR)

The first commit added a hero terminal mockup, eyebrow badge, secondary CTA, card hover polish, section-title accents, and a pricing "custom plan" path. The alignment commit re-tones these to the design-system language.

Verification

  • npm run build ✓ (SSR + prerender, exit 0)
  • Visually verified hero, sections, cards, pricing, /docs, /privacy

🤖 Generated with Claude Code

mashkovd added 2 commits May 29, 2026 08:02
…d polish

- Hero: add eyebrow badge, secondary 'Read the docs' CTA, and an
  on-brand terminal mockup showing the push/ask-AI/live loop
- Add a fixed ambient blueprint-grid + glow background for depth
- BaseCard: universal hover lift, accent border and top sheen
- BaseSection: accent underline beneath section titles
- Pricing: give the single Free plan an intentional centered layout
  with a 'custom plan' contact path beneath
- i18n: add hero.badge, hero.cta_secondary, pricing.custom.* (en + ru)
Adopt the canonical mctl-design tokens (the dependency-free vendoring
pattern mctl-telegram/mctl-instruments use) so mctl-web stops diverging:

- Palette: ink #0a0b0d + cyan #00e5ff (was the #050816/#00f5ff fork);
  neutral hairline borders instead of cyan glass borders
- Type: Geist for display/body, Instrument Serif available for ledes,
  JetBrains Mono retained for chrome (nav, eyebrows, code, terminal)
- Replace cyan glow/sheen with the system's restrained hairline language;
  recolour the ambient grid to a neutral blueprint tone
- Load Geist + Instrument Serif fonts alongside JetBrains Mono
@mashkovd

Copy link
Copy Markdown
Member Author

@claude review

@claude

claude Bot commented May 29, 2026 •

Copy link
Copy Markdown

Claude finished @mashkovd's task in 3m 9s —— View job


Code Review

  • Gather context
  • Read changed files and diff
  • Analyse for correctness, security, and conventions
  • Post inline findings
  • Post summary verdict

Summary

2 P1 — none
3 P2 — must fix before merge
2 P3 — nice to have

Has P2 findings, changes requested.

The design-token migration in base.scss is solid and the new hero layout/animations are well-structured (reduced-motion, aria-hidden, BEM naming). Two categories of issues need attention before this lands:

P2 — stale hardcoded colours in BaseCard.vue

The PR defines --color-glass-border: var(--color-line) and states "neutral hairline borders instead of cyan glass borders", but BaseCard.vue was not updated to use the new token. Three raw rgba(0, 245, 255, …) values from the old #00f5ff palette remain:

  • Line 32 — base border (the one visible on every card)
  • Line 59 — --highlighted variant's box-shadow
  • Lines 72 & 79 — --dark variant's gradient and hover shadow

These should all be replaced with design tokens (var(--color-glass-border), var(--color-accent-soft)) — see inline comments.

P2 — terminal body will render in Geist, not monospace

base.scss in this PR switches body { font-family } from var(--font-mono) to var(--font-display). .hero-terminal__body inherits that change and will display all terminal lines in the proportional Geist typeface, breaking the terminal aesthetic. A one-liner fix: add font-family: var(--font-mono) to the &__body block.

P3 — terminal background not tokenised

rgba(8, 12, 26, 0.85) on .hero-terminal diverges from every token in base.scss. Either map it to var(--color-terminal) or name a new token.

P3 — white-space: nowrap may clip product copy on narrow viewports

The longest demo line (mctl ask "roll my-app back to v1.4.2") can be clipped with an ellipsis on sub-380px screens, silently hiding the key product message. Worth shortening or switching to pre-wrap.

No security issues, no XSS vectors (v-html source is static translation strings), no Node.js API usage in the Worker.

&__body {
padding: 1.5rem 1.5rem 1.75rem;
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 →

Comment thread app/components/shared/BaseCard.vue Outdated
@@ -30,9 +30,30 @@ defineProps<Props>();
background-color: var(--card-bg);
border-radius: 8px;
border: 1px solid rgba(0, 245, 255, 0.2);

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 — base border still uses the old #00f5ff palette value, not the new design token

The PR states "neutral hairline borders instead of cyan glass borders" and defines --color-glass-border: var(--color-line) (#1f242b). This line was not updated, so every un-highlighted card still has a cyan-glowing border — contrary to the stated design goal.

Suggested change
border: 1px solid rgba(0, 245, 255, 0.2);
border: 1px solid var(--color-glass-border);

Fix this →

Comment thread app/components/shared/BaseCard.vue Outdated

&--highlighted {
border-color: var(--color-accent);
box-shadow: 0 0 30px rgba(0, 245, 255, 0.2);

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 — --highlighted and --dark variants still use old #00f5ff hardcoded values

Three places below this line were not updated to the new palette:

  • Line 59: box-shadow: 0 0 30px rgba(0, 245, 255, 0.2) — old cyan glow
  • Line 72: rgba(0, 245, 255, 0.05) in the --dark gradient
  • Line 79: rgba(0, 245, 255, 0.1) in the --dark hover shadow

Suggested updates:

Suggested change
box-shadow: 0 0 30px rgba(0, 245, 255, 0.2);
box-shadow: 0 0 30px var(--color-accent-soft);

And for the --dark variant's raw rgba values, replace with var(--color-accent-soft) or introduce a dedicated --color-accent-dim token.

Fix this →

Comment thread app/components/main/HeroBlock.vue Outdated
margin: 4rem auto 0;

text-align: left;
background: rgba(8, 12, 26, 0.85);

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 — terminal background uses a hardcoded rgba not present in the token set

rgba(8, 12, 26, 0.85) is darker than --color-terminal (rgba(21, 24, 29, 0.85)) and darker than --color-bg (#0a0b0d). If this intentional divergence should persist, define a named token (e.g. --color-terminal-deep) in base.scss. As-is, any future palette adjustment won't reach this element.

Comment thread app/components/main/HeroBlock.vue Outdated

&__line {
margin: 0;
white-space: nowrap;

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 — white-space: nowrap + ellipsis will silently clip terminal content on narrow viewports

The longest line — mctl ask "roll my-app back to v1.4.2" — overflows on viewports ≤ ~360px even at 0.72rem. The ellipsis makes it look fine at a glance but hides copy that demonstrates the product. Consider allowing wrapping (white-space: pre-wrap) for the body lines, or shortening the demo strings to fit ~320px.

- BaseCard: replace remaining hardcoded #00f5ff borders/glows with
  --color-glass-border / --color-accent-soft / --shadow-card-hover (P2)
- Hero terminal body: force --font-mono so it doesn't inherit Geist (P2)
- Tokenise the terminal background to --color-terminal (P3)
- Let terminal lines wrap instead of clipping with an ellipsis on
  narrow viewports (P3)
@claude

claude Bot commented May 29, 2026 •

Copy link
Copy Markdown

Claude finished @mashkovd's task in 2m 8s —— View job


Re-review (post-synchronize)

  • Read changed files and diff
  • Check if previous P2 findings were addressed
  • Analyse for any new issues
  • Post inline findings
  • Post summary verdict

Summary

0 P1 — none
0 P2 — all previously flagged issues are fixed
2 P3 — non-blocking

The fix commit (894ddec) cleanly resolves both P2s from the first review:

  • BaseCard hardcoded rgba(0, 245, 255, …) values — all three (base border, --highlighted shadow, --dark gradient/hover) replaced with var(--color-glass-border), var(--color-accent-soft), and var(--shadow-card-hover). ✓
  • Terminal body rendering in Geist — font-family: var(--font-mono) added to &__body. ✓

The previously-noted P3s are also resolved: terminal background now uses var(--color-terminal) and white-space: nowrap was never present in the final code.

Two minor P3s remain (see inline comments):

  1. hero-block__badge inherits Geist from body; the PR's stated design intent (and the BaseSection overline in the same PR) puts eyebrow-style elements in mono.
  2. hero-block__glow gradient uses a raw rgba(0, 229, 255, 0.05) not present in the token set.

Neither blocks merge. No P1/P2 findings — good to merge.

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;

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%);

@mashkovd

Copy link
Copy Markdown
Member Author

@claude review

@mashkovd
mashkovd merged commit 2734243 into main May 29, 2026
2 checks passed
@mashkovd
mashkovd deleted the feat/visual-polish branch May 29, 2026 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant