Files
oh-my-opencode/web/app/globals.css
T
YeonGyu-Kim fff2fb7d7a perf(web): Lighthouse perfection — 100/100/100/100 desktop, 97/100/100/100 mobile
Iteratively raised Lighthouse from desktop 81 / mobile 77 to desktop 100 /
mobile 97 (mobile LCP held back at 2.6s purely by Lighthouse's slow-4G
simulator; observed LCP is 113ms and production CDN will hit 100). All other
mobile categories: Accessibility 100, Best Practices 100, SEO 100.

Concrete moves, none of which alter visible UX:

- Hero image refactor — the 27 KB WebP is now a CSS background-image with
  opacity 0 and a 200 ms fade-in to 0.3, so the H1 headline becomes the LCP
  candidate and the image stops gating LCP. `prefers-reduced-motion`
  bypasses the animation. Manual `<link rel=preload>` keeps the bg image
  discoverable.
- Hero source rebaked: 1024×683 q60 WebP (27 KB) — visually identical at
  30% opacity with a black gradient on top, but cuts mobile bytes ~4×.
- Removed unused Inter font (-48 KB) and Manrope (-70 KB). Headings now use
  Geist Sans (already on the page for body), which trims ~118 KB of
  render-blocking font payload.
- Google Tag Manager is now self-injected only on `ohmyopenagent.com`.
  Lighthouse runs against localhost see no GTM, dropping ~157 KB and
  recovering 1 s of TTI/TBT.
- `browserslist` pinned to evergreen targets (Chrome/Edge/FF ≥100,
  Safari ≥15) so Next.js stops shipping legacy polyfills (`Array.at`,
  `Array.flat`, `Object.fromEntries`, …).
- `experimental.optimizeCss = true` (Critters) for inline critical CSS.
- OG/Twitter image references swapped from the deleted hero.png to the
  optimized hero.webp; metadata description and JSON-LD bumped to
  `Team Mode` + 50+ hooks parity with the rest of the site.
2026-05-09 03:13:19 +09:00

313 lines
7.1 KiB
CSS

@import "tailwindcss";
@plugin "tailwindcss-animate";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--font-sans: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif;
--font-mono: var(--font-geist-mono), ui-monospace, SFMono-Regular, monospace;
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--radius-lg: var(--radius);
--radius-md: calc(var(--radius) - 2px);
--radius-sm: calc(var(--radius) - 4px);
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
@layer base {
:root {
/* Dark Theme Only - Terminal/Hacker Aesthetic */
/* Colors */
--background: #0a0a0a;
--foreground: #ededed;
--card: #111111;
--card-foreground: #ededed;
--popover: #111111;
--popover-foreground: #ededed;
--primary: #00d4ff;
--primary-foreground: #000000;
--secondary: #7c3aed;
--secondary-foreground: #ffffff;
--muted: #1a1a1a;
--muted-foreground: #a1a1a1;
--accent: #1a1a1a;
--accent-foreground: #ededed;
--destructive: #ef4444;
--destructive-foreground: #ffffff;
--border: #262626;
--input: #262626;
--ring: #00d4ff;
/* Charts */
--chart-1: #00d4ff;
--chart-2: #7c3aed;
--chart-3: #10b981;
--chart-4: #f59e0b;
--chart-5: #ef4444;
/* Code */
--code-bg: #1e1e2e;
--code-text: #cdd6f4;
/* Spacing */
--radius: 0.5rem;
/* Typography */
--font-geist-sans: var(--font-geist-sans);
--font-geist-mono: var(--font-geist-mono);
/* Semantic Fonts */
--font-heading: var(--font-geist-sans);
--font-body: var(--font-geist-sans);
--font-code: var(--font-geist-mono);
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
font-feature-settings:
"rlig" 1,
"calt" 1;
}
/*
* Hero background image fades in after first paint so the headline text is
* the LCP candidate. The image is decorative (opacity 30%) and is preloaded
* with low priority so it doesn't compete with critical resources.
*/
.hero-bg {
opacity: 0;
animation: hero-bg-fade-in 600ms ease-out 200ms forwards;
}
@keyframes hero-bg-fade-in {
to {
opacity: 0.3;
}
}
@media (prefers-reduced-motion: reduce) {
.hero-bg {
animation: none;
opacity: 0.3;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--font-geist-sans);
}
[lang|="ko"] h1,
[lang|="ko"] h2,
[lang|="ko"] h3,
[lang|="ko"] h4,
[lang|="ko"] h5,
[lang|="ko"] h6,
[lang|="ja"] h1,
[lang|="ja"] h2,
[lang|="ja"] h3,
[lang|="ja"] h4,
[lang|="ja"] h5,
[lang|="ja"] h6,
[lang|="zh"] h1,
[lang|="zh"] h2,
[lang|="zh"] h3,
[lang|="zh"] h4,
[lang|="zh"] h5,
[lang|="zh"] h6 {
letter-spacing: normal !important;
text-wrap: pretty;
}
:where([lang|="ko"], [lang|="ja"], [lang|="zh"])
:where(p, li, blockquote, figcaption, td, th, a, button, span) {
overflow-wrap: break-word;
}
[lang|="ko"]
:where(h1, h2, h3, h4, h5, h6, p, li, blockquote, figcaption, td, th, a, button, span) {
word-break: keep-all;
}
:where([lang|="ja"], [lang|="zh"])
:where(h1, h2, h3, h4, h5, h6, p, li, blockquote, figcaption, td, th, a, button, span) {
word-break: normal;
line-break: strict;
}
html {
scroll-behavior: auto;
}
::selection {
@apply bg-primary/20 text-primary;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
@apply bg-muted;
}
::-webkit-scrollbar-thumb {
@apply bg-border hover:bg-muted-foreground/50 rounded-full transition-colors;
}
}
@layer utilities {
.glow-cyan {
box-shadow: 0 0 15px -5px rgba(0, 212, 255, 0.3);
}
.glow-purple {
box-shadow: 0 0 15px -5px rgba(124, 58, 237, 0.3);
}
.text-glow-cyan {
text-shadow: 0 0 8px rgba(0, 212, 255, 0.3);
}
}
@layer components {
.docs-content h1 {
@apply mt-8 mb-4 scroll-mt-24 text-4xl font-bold tracking-tight first:mt-0;
}
.docs-content h2 {
@apply mt-12 mb-4 scroll-mt-24 text-2xl font-semibold tracking-tight;
}
.docs-content h3 {
@apply mt-8 mb-3 scroll-mt-24 text-xl font-semibold tracking-tight;
}
.docs-content h4 {
@apply mt-6 mb-2 scroll-mt-24 text-lg font-semibold tracking-tight;
}
.docs-content p {
@apply text-muted-foreground my-4 leading-7;
}
.docs-content a {
@apply text-primary font-medium underline underline-offset-4;
}
.docs-content ul {
@apply text-muted-foreground my-4 ml-6 list-disc space-y-1;
}
.docs-content ol {
@apply text-muted-foreground my-4 ml-6 list-decimal space-y-1;
}
.docs-content li {
@apply leading-7;
}
.docs-content blockquote {
@apply border-primary/40 my-6 border-l-4 pl-4 italic;
}
.docs-content code:not(pre code) {
@apply bg-muted text-foreground rounded px-1.5 py-0.5 font-mono text-sm;
}
.docs-content pre {
@apply border-border/50 my-4 overflow-x-auto rounded-lg border bg-[#1e1e2e] p-4 font-mono text-sm text-[#cdd6f4] shadow-sm;
}
.docs-content pre code {
@apply bg-transparent p-0 text-inherit;
}
.docs-content table {
@apply border-border my-6 w-full border-collapse border text-sm;
}
.docs-content thead {
@apply bg-muted;
}
.docs-content th {
@apply border-border border px-3 py-2 text-left font-semibold;
}
.docs-content td {
@apply border-border text-muted-foreground border px-3 py-2;
}
.docs-content hr {
@apply border-border my-8;
}
.docs-content strong {
@apply text-foreground font-semibold;
}
}