From ceffb2a3f3dd71abeee165e5720bad5406c47cae Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Sun, 14 Jun 2026 21:22:58 +0700 Subject: [PATCH] refactor(legacy): apply v6 design to all inner pages (delete bento components) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per user: 'เราไม่ต้องการ legacy design น่ะ เพราะมีดีไชน์ใหม่แล้วไง' - New v6 design must apply to EVERY page, not just index PHASE A — Add CSS compatibility aliases (~600 lines) ================================================== fx-system.css grew from 0.05MB → 0.12MB with 3 new alias blocks for legacy class names that pages still use: 1. LEGACY → v6 ALIASES .section, .section-bento, .section-soft, .section-yellow .section-header, .section-badge, .section-title, .section-desc .reveal, .hero-content, .hero-badge, .hero-grid .service-stack + .service-stack-{item,num,icon,body,title,bullets} .portfolio-card-{grid,top,badge,arrow,name,industry,highlight} .contact-form, .form-{group,label,input,row,success}, .btn, .btn-{primary,outline-dark} .filter-section, .filter-bar, .filter-btn .info-icon, .checklist All styled with v6 design tokens (--ink, --paper, --coral, --brand-yellow, --line-2, --paper-2, etc.) 2. BENTO COMPONENT ALIASES .bento-grid, .bento-tile, .span-{3,4,5,6,7,8,12}, .rows-{2,3} .surface-{white,soft,yellow,purple,purple-soft,teal,teal-soft,mint,dark,coral} .tile-{eyebrow,title,body,link}, .mega-cta All render via CSS Grid 12-col + v6 surface treatments Children (.tile-eyebrow, .tile-title, .tile-body) get v6 typography (Kanit 800 for titles, JetBrains Mono 700 for eyebrows, Itim for em accents). 3. DARK MODE OVERRIDES html.dark .section-soft/.filter-section: var(--paper-2) html.dark .section-badge/.filter-btn.active: yellow html.dark .contact-form .form-input: dark inputs html.dark .bento-tile.surface-{soft,purple-soft,yellow}: dark variants PHASE B — Replace legacy components with inline divs ================================================== Deleted components (no longer imported by anyone): - src/components/BentoGrid.astro - src/components/BentoTile.astro - src/components/DecoOrb.astro - src/components/PageHero.astro Replaced in 7 pages (mechanical regex sweep): - services/[slug].astro - contact.astro - faq.astro - blog/index.astro - blog/[slug].astro - privacy.astro - terms.astro JSX transforms: - ... →
...
- →
- → (deleted, was decorative empty) - Removed unused BentoGrid/BentoTile/DecoOrb imports Cleaned orphan comments referencing deleted components: - // use data-parallax-speed from DecoOrb - - /* FAQ inside BentoTile */ FINAL AUDIT =========== - 0 legacy component refs in src/ - Build: 22 pages, 1.98s, 0 errors - All 11 pages have v6 styling (via direct fx-* or via aliases) Result: every page now uses the v6 design system consistently. No more yellow DecorativeOrbs, no more BentoTile grid overlap, no more PageHero/KineticHero mixing. Visual continuity across all 11 pages. --- src/components/BentoGrid.astro | 39 --- src/components/BentoTile.astro | 169 ---------- src/components/DecoOrb.astro | 68 ---- src/components/PageHero.astro | 195 ------------ src/pages/blog/[slug].astro | 57 ++-- src/pages/blog/index.astro | 53 ++- src/pages/contact.astro | 146 +++++---- src/pages/faq.astro | 70 ++-- src/pages/privacy.astro | 37 +-- src/pages/services/[slug].astro | 39 +-- src/pages/terms.astro | 37 +-- src/styles/fx-system.css | 549 ++++++++++++++++++++++++++++++++ 12 files changed, 761 insertions(+), 698 deletions(-) delete mode 100644 src/components/BentoGrid.astro delete mode 100644 src/components/BentoTile.astro delete mode 100644 src/components/DecoOrb.astro delete mode 100644 src/components/PageHero.astro diff --git a/src/components/BentoGrid.astro b/src/components/BentoGrid.astro deleted file mode 100644 index c1764de..0000000 --- a/src/components/BentoGrid.astro +++ /dev/null @@ -1,39 +0,0 @@ ---- -/** - * BentoGrid — 12-column asymmetric bento grid container. - * Use as children. - * - * Example: - * - * ... - * ... - * - */ ---- - -
- -
- - diff --git a/src/components/BentoTile.astro b/src/components/BentoTile.astro deleted file mode 100644 index 1d0c720..0000000 --- a/src/components/BentoTile.astro +++ /dev/null @@ -1,169 +0,0 @@ ---- -/** - * BentoTile — a single bento grid cell. - * - * Props: - * span: 3 | 4 | 5 | 6 | 7 | 8 | 12 (default 6) - * rows: 1 | 2 | 3 (default 1) - * surface: 'white' | 'soft' | 'yellow' | 'purple' | 'purple-soft' | 'teal' | 'mint' | 'dark' | 'coral' - * minHeight: optional inline min-height CSS value - * eyebrow: optional small uppercase label above title - * title: optional H2 title - * reveal: boolean, animate on scroll into view (default true) - * - * Example: - * - *

...content...

- *
- */ - -interface Props { - span?: 3 | 4 | 5 | 6 | 7 | 8 | 12; - rows?: 1 | 2 | 3; - surface?: 'white' | 'soft' | 'yellow' | 'purple' | 'purple-soft' | 'teal' | 'teal-soft' | 'mint' | 'dark' | 'coral'; - minHeight?: string; - eyebrow?: string; - title?: string; - reveal?: boolean; - class?: string; -} - -const { - span = 6, - rows = 1, - surface = 'white', - minHeight, - eyebrow, - title, - reveal = true, - class: className = '', -} = Astro.props; - -const spanClass = `span-${span}`; -const rowsClass = rows > 1 ? `rows-${rows}` : ''; -const surfaceClass = `surface-${surface}`; -const revealClass = reveal ? 'reveal' : ''; ---- - -
- {eyebrow &&
{eyebrow}
} - {title &&

{title}

} -
- -
-
- - diff --git a/src/components/DecoOrb.astro b/src/components/DecoOrb.astro deleted file mode 100644 index 31d20a3..0000000 --- a/src/components/DecoOrb.astro +++ /dev/null @@ -1,68 +0,0 @@ ---- -/** - * DecoOrb — decorative parallax blur orb for section backgrounds. - * Pure decoration, never blocks clicks, always behind content. - * - * Props: - * color: 'yellow' | 'soft' | 'purple' | 'mint' | 'teal' (default 'yellow') - * size: CSS dimension (default '400px') - * speed: parallax speed 0.0–1.0 (default 0.4) - * position: { top?, right?, bottom?, left? } CSS positions - * blur: CSS blur value (default '60px') - * opacity: CSS opacity 0–1 (default 0.5) - * - * Example: - * - */ - -interface Props { - color?: 'yellow' | 'soft' | 'purple' | 'mint' | 'teal'; - size?: string; - speed?: number; - position?: { top?: string; right?: string; bottom?: string; left?: string }; - blur?: string; - opacity?: number; -} - -const { - color = 'yellow', - size = '400px', - speed = 0.4, - position = {}, - blur = '60px', - opacity = 0.5, -} = Astro.props; - -const styleStr = [ - `width: ${size};`, - `height: ${size};`, - `filter: blur(${blur});`, - `opacity: ${opacity};`, - position.top ? `top: ${position.top};` : '', - position.right ? `right: ${position.right};` : '', - position.bottom ? `bottom: ${position.bottom};` : '', - position.left ? `left: ${position.left};` : '', -].join(' '); ---- - -
- - diff --git a/src/components/PageHero.astro b/src/components/PageHero.astro deleted file mode 100644 index 75a380b..0000000 --- a/src/components/PageHero.astro +++ /dev/null @@ -1,195 +0,0 @@ ---- -/** - * MOREMINIMORE - PAGE HERO COMPONENT (LIGHT THEME + ANIMATIONS) - * White bg + dark text + yellow accent line. Animated on load. - */ - -interface Props { - badge?: string; - title: string; - subtitle?: string; -} - -const { - badge, - title, - subtitle, -} = Astro.props; - -// Split title into words for kinetic animation -const titleWords = title.split(' '); ---- - -
-
-
-
- -
- {badge && ( - {badge} - )} -

- {titleWords.map((word, index) => ( - - - {word} - - - ))} -

- {subtitle && ( -

{subtitle}

- )} -
- - -
-
-
-
- - diff --git a/src/pages/blog/[slug].astro b/src/pages/blog/[slug].astro index 1264797..78c17d2 100644 --- a/src/pages/blog/[slug].astro +++ b/src/pages/blog/[slug].astro @@ -1,9 +1,6 @@ --- import Base from '../../layouts/Base.astro'; import Hero from '../../components/Hero.astro'; -import BentoGrid from '../../components/BentoGrid.astro'; -import BentoTile from '../../components/BentoTile.astro'; -import DecoOrb from '../../components/DecoOrb.astro'; import { getCollection, render } from 'astro:content'; const { slug } = Astro.params; @@ -51,8 +48,8 @@ function surfaceFor(i: number) { {post.data.image && (
- - + +
{post.data.title} @@ -62,22 +59,26 @@ function surfaceFor(i: number) { )}
- - + +
- +
+ - +
+
{formattedDate}
- + +
- +
+

ดิจิทัลเอเจนซี่ที่ช่วยให้ธุรกิจไทยเติบโตด้วยเทคโนโลยีสมัยใหม่

ดูเพิ่มเติม @@ -89,25 +90,29 @@ function surfaceFor(i: number) { ติดต่อเรา 080-995-5945
-
- + +
+ +
{related.length > 0 && (
- - + +
บทความที่เกี่ยวข้อง

อ่านต่อ เนื้อหาใกล้เคียง

- +
+ {related.map((r, i) => ( - +
+
{r.data.image && (
@@ -118,10 +123,12 @@ function surfaceFor(i: number) { {new Date(r.data.date).toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })}
- + +
))} - + +
)} @@ -296,15 +303,5 @@ function surfaceFor(i: number) { diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index e305fdb..3f4f074 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -1,9 +1,6 @@ --- import Base from '../../layouts/Base.astro'; import Hero from '../../components/Hero.astro'; -import BentoGrid from '../../components/BentoGrid.astro'; -import BentoTile from '../../components/BentoTile.astro'; -import DecoOrb from '../../components/DecoOrb.astro'; import { getCollection } from 'astro:content'; const blogPosts = await getCollection('blog'); @@ -25,12 +22,14 @@ function surfaceFor(i: number) { {sortedPosts.length > 0 && (
- - + +
- - +
+ +
+
{sortedPosts[0].data.image && ( @@ -38,9 +37,11 @@ function surfaceFor(i: number) { )}
- + +
+ +
-

{sortedPosts[0].data.excerpt}

@@ -55,16 +56,18 @@ function surfaceFor(i: number) {
- - + +
+ +
)}
- - + +
บทความทั้งหมด @@ -72,10 +75,12 @@ function surfaceFor(i: number) {
{sortedPosts.length > 1 && ( - +
+ {sortedPosts.slice(1).map((post, i) => ( - +
+
{post.data.image && (
@@ -87,10 +92,12 @@ function surfaceFor(i: number) { {new Date(post.data.date).toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })}
- + +
))} - + +
)}
@@ -259,15 +266,5 @@ function surfaceFor(i: number) { diff --git a/src/pages/contact.astro b/src/pages/contact.astro index bc07c44..8331c20 100644 --- a/src/pages/contact.astro +++ b/src/pages/contact.astro @@ -2,10 +2,6 @@ import Base from '../layouts/Base.astro'; import Hero from '../components/Hero.astro'; import Icon from '../components/Icon.astro'; -import BentoGrid from '../components/BentoGrid.astro'; -import BentoTile from '../components/BentoTile.astro'; -import DecoOrb from '../components/DecoOrb.astro'; - // Service options for the form — with lucide icon names const serviceOptions = [ { value: 'webdev', label: 'AI-Enhanced Website (เว็บ + Chatbot + SEO)', icon: 'globe' }, @@ -27,40 +23,50 @@ const serviceOptions = [
- - + +
- - +
+ +
+

คนที่อยากคุยเร็ว ๆ แบบเป็นกันเอง

ตอบใน 30 นาที (เวลาทำการ)

ทักเลย → - - + +
+
+

คนที่อยากคุยยาว ๆ 5–10 นาที ถามตอบสด

รับสายทันที หรือโทรกลับภายใน 2 ชม.

โทรเลย → - - + +
+
+

คนที่อยากส่งรายละเอียดโปรเจกต์ + ไฟล์แนบ

ตอบภายใน 1 วันทำการ

ส่งอีเมล → - - + +
+ +
- - + +
- +
+ - +
+

เราจะตอบกลับภายใน 2 ชั่วโมง (เวลาทำการ)

@@ -126,86 +132,113 @@ const serviceOptions = [

ส่งแล้ว!

เราจะตอบกลับภายใน 2 ชั่วโมง (ในเวลาทำการ) ถ้าเร่งด่วน ทัก LINE @moreminimore ครับ

-
+ +
+ +
- -

โทรคุยสดได้เลย

จ-ศ 09:00-18:00

โทรเลย → -
+ +
+ +
-

เหมาะกับส่งรายละเอียดโปรเจกต์ + ไฟล์แนบ

ตอบภายใน 1 วันทำการ

ส่งอีเมล → -
+ +
+ +
-

เร็วที่สุด ตอบใน 30 นาที (เวลาทำการ)

นอกเวลา? ทักทิ้งไว้ได้

ทักเลย → -
+ +
+ +
-

นอกเวลาทำการ? ทัก LINE ทิ้งไว้ได้ ตอบเช้าวันถัดไป

53 หมู่ 1 ต.บ้านแพ้ว อ.บ้านแพ้ว สมุทรสาคร 74120 · นัดเจอล่วงหน้า

-
- + +
+ +
- - + +
หลังส่งฟอร์ม

3 ขั้นตอนถัดไป — ไม่มีอะไรซับซ้อน

- - +
+ +
+

คนจริง (ไม่ใช่ Bot) จะตอบ — ถามคำถามเพิ่ม 2–3 ข้อ เพื่อเข้าใจปัญหาคุณ

- - + +
+
+

คุยผ่าน Zoom / โทร / นัดเจอที่ออฟฟิศ (กรุงเทพ / สมุทรสาคร) — ไม่มี script sales

- - + +
+
+

เอกสาร PDF ที่ระบุ scope, timeline, ราคา — ไม่ชอบตรงไหนคุยกันแก้ได้

- - + +
+ +

ถ้าไม่ตรง → เราจะบอกตรง ๆ ว่า "ไม่เหมาะ" และแนะนำทางเลือกอื่น

- - + +
ก่อนกดส่ง

4 คำถามที่คนถาม ก่อน กดส่งฟอร์ม

- - +
+ +
+

ไม่ คุยแล้วคุณไม่ชอบก็ไม่เป็นไร ไม่มี follow-up ไม่มีขายของเพิ่ม

- - + +
+
+

ทัก LINE @moreminimore ตรง ๆ จะเร็วกว่า — หรือโทร 080-995-5945

- - + +
+
+

จันทร์-ศุกร์ 09:00-18:00 ปกติ ถ้าคุณต่างจังหวัด/ต่างประเทศ นัดนอกเวลาได้ บอกล่วงหน้า 1–2 วัน

- - + +
+
+

ไม่ต้องเตรียมอะไรเลย แค่บอกธุรกิจคุณทำอะไร ปวดหัวเรื่องอะไร งบประมาณเท่าไหร่ ที่เหลือเราถามเอง

- - + +
+ +
@@ -417,17 +450,6 @@ const serviceOptions = [ diff --git a/src/pages/privacy.astro b/src/pages/privacy.astro index f01bca9..58d3f14 100644 --- a/src/pages/privacy.astro +++ b/src/pages/privacy.astro @@ -1,9 +1,6 @@ --- import Base from '../layouts/Base.astro'; import Hero from '../components/Hero.astro'; -import BentoGrid from '../components/BentoGrid.astro'; -import BentoTile from '../components/BentoTile.astro'; -import DecoOrb from '../components/DecoOrb.astro'; --- @@ -14,11 +11,13 @@ import DecoOrb from '../components/DecoOrb.astro'; showStats={false} />
- - + +
- - +
+ +
+

บริษัท มอร์มินิมอร์ จำกัด ให้ความสำคัญกับการคุ้มครองข้อมูลส่วนบุคคลของท่าน

@@ -53,9 +52,11 @@ import DecoOrb from '../components/DecoOrb.astro';

ท่านมีสิทธิในการเข้าถึง แก้ไข ลบ หรือระงับการใช้ข้อมูลส่วนบุคคลของท่าน กรุณาติดต่อเราผ่านช่องทางที่ระบุในเว็บไซต์

- + +
+ +
-

ชื่อเอกสาร: นโยบายความเป็นส่วนตัว

มีผลบังคับใช้: 5 พฤษภาคม 2569

@@ -68,8 +69,10 @@ import DecoOrb from '../components/DecoOrb.astro';
  • สิทธิของท่าน
  • -
    - + +
    + +
    @@ -154,15 +157,5 @@ import DecoOrb from '../components/DecoOrb.astro'; diff --git a/src/pages/services/[slug].astro b/src/pages/services/[slug].astro index 33fa7b7..e8814b3 100644 --- a/src/pages/services/[slug].astro +++ b/src/pages/services/[slug].astro @@ -1,8 +1,5 @@ --- import Base from '../../layouts/Base.astro'; -import BentoGrid from '../../components/BentoGrid.astro'; -import BentoTile from '../../components/BentoTile.astro'; -import DecoOrb from '../../components/DecoOrb.astro'; import Icon from '../../components/Icon.astro'; import { getCollection, render } from 'astro:content'; @@ -325,8 +322,8 @@ const featureList = data.features || data.services || [];
    - - + +
    @@ -374,8 +371,8 @@ const featureList = data.features || data.services || []; {data.services && (
    - - + +
    บริการที่คุณได้รับ @@ -408,8 +405,8 @@ const featureList = data.features || data.services || []; {(data.realPortfolio || data.techOptions) && (
    - - + +
    {data.techOptions && ( @@ -471,8 +468,8 @@ const featureList = data.features || data.services || []; {data.targets && (
    - - + +
    เหมาะกับใคร @@ -495,8 +492,8 @@ const featureList = data.features || data.services || [];
    - - + +
    {data.pricing ? ( <> @@ -561,8 +558,8 @@ const featureList = data.features || data.services || [];
    - - + +
    FAQ @@ -1589,15 +1586,5 @@ const featureList = data.features || data.services || []; diff --git a/src/pages/terms.astro b/src/pages/terms.astro index 5550234..47bc30b 100644 --- a/src/pages/terms.astro +++ b/src/pages/terms.astro @@ -1,9 +1,6 @@ --- import Base from '../layouts/Base.astro'; import Hero from '../components/Hero.astro'; -import BentoGrid from '../components/BentoGrid.astro'; -import BentoTile from '../components/BentoTile.astro'; -import DecoOrb from '../components/DecoOrb.astro'; --- @@ -14,11 +11,13 @@ import DecoOrb from '../components/DecoOrb.astro'; showStats={false} />
    - - + +
    - - +
    + +
    +

    ชื่อเว็บไซต์: MoreminiMore | เว็บไซต์: https://www.moreminimore.com | บริษัท: MoreminiMore Co.,Ltd.

    @@ -57,9 +56,11 @@ import DecoOrb from '../components/DecoOrb.astro';

    หากมีคำถามเกี่ยวกับเงื่อนไขการให้บริการ กรุณาติดต่อเราที่ contact@moreminimore.com หรือ 080-995-5945

    - + +
    + +
    -

    ชื่อเอกสาร: เงื่อนไขการให้บริการ

    มีผลบังคับใช้: 5 พฤษภาคม 2569

    @@ -75,8 +76,10 @@ import DecoOrb from '../components/DecoOrb.astro';
  • ติดต่อเรา
  • -
    - + +
    + +
    @@ -151,15 +154,5 @@ import DecoOrb from '../components/DecoOrb.astro'; diff --git a/src/styles/fx-system.css b/src/styles/fx-system.css index 1a95cb6..2004c07 100644 --- a/src/styles/fx-system.css +++ b/src/styles/fx-system.css @@ -662,6 +662,554 @@ html.dark body { background: var(--body-bg); color: var(--body-fg); } Now: business consulting tagline. */ .fx-hero-content::after { content: 'AI · MARKETING · RESULTS' !important; } +/* ============================================ + LEGACY → v6 COMPATIBILITY ALIASES (added 2026-06-13) + Per user "ไม่ต้องการ legacy design น่ะ" — we replace + the bento components entirely. But many inner pages + (blog/[slug], blog/index, contact, faq, privacy, terms, + services/[slug]) still use v7-5's class names like + .section-bento, .section-header, .reveal, etc. + + Instead of rewriting every page content, we add + COMPATIBILITY ALIASES that map legacy class names to + the v6 design system. Pages keep their structure, + but styling comes from fx-system tokens (--ink, --paper, + --coral, --brand-yellow, --line-2, etc.) so every page + gets the same v6 look automatically. + + These rules are LAST in the file so they win cascade + when overlapping with any base v7-5 rules above. + ============================================ */ + +/* ----- Section containers ----- */ +.section { + padding: 64px 32px; + position: relative; + overflow: hidden; +} +.section-bento { + padding: 64px 32px; + position: relative; + overflow: hidden; +} +.section-soft { + background: var(--paper-2); + border-top: 1.5px solid var(--ink); + border-bottom: 1.5px solid var(--ink); +} +.section-yellow { + background: var(--brand-yellow); + border-top: 2px solid var(--ink); + border-bottom: 2px solid var(--ink); +} + +/* ----- Section headers (eyebrow / title / desc) ----- */ +.section-header { + max-width: 1200px; + margin: 0 auto 32px; + text-align: center; +} +.section-badge { + display: inline-block; + font: 700 10px/1 'JetBrains Mono', monospace; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--ink); + background: var(--brand-yellow); + border: 1.5px solid var(--ink); + padding: 6px 12px; + margin-bottom: 16px; +} +.section-title { + font: 900 clamp(28px, 4vw, 44px)/1.1 'Kanit', sans-serif; + letter-spacing: -1.5px; + color: var(--ink); + margin: 0 0 16px; +} +.section-title .highlight { + color: var(--coral); + text-decoration: underline; + text-decoration-color: var(--ink); + text-underline-offset: 6px; + text-decoration-thickness: 4px; +} +.section-desc { + font: 400 16px/1.6 'Kanit', sans-serif; + color: var(--text-dim); + max-width: 700px; + margin: 0 auto; +} + +/* ----- Reveal animation (legacy IntersectionObserver trigger) ----- */ +.reveal { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; +} +.reveal.revealed { + opacity: 1; + transform: translateY(0); +} + +/* ----- Hero (custom inner-page hero) ----- */ +.hero-content { + background: var(--paper); + border: 1.5px solid var(--ink); + padding: 32px; + position: relative; +} +.hero-badge { + display: inline-block; + font: 700 10px/1 'JetBrains Mono', monospace; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--ink); + background: var(--brand-yellow); + border: 1.5px solid var(--ink); + padding: 6px 12px; + margin-bottom: 16px; +} +.hero-grid { + display: grid; + grid-template-columns: 1.5fr 1fr; + gap: 32px; + max-width: 1200px; + margin: 32px auto 0; +} +@media (max-width: 1024px) { .hero-grid { grid-template-columns: 1fr; } } + +/* ----- Service stack (custom service card layout) ----- */ +.service-stack { + display: flex; + flex-direction: column; + gap: 16px; + max-width: 800px; + margin: 0 auto; +} +.service-stack-item { + display: flex; + align-items: flex-start; + gap: 16px; + background: var(--paper); + border: 1.5px solid var(--ink); + padding: 24px; + transition: all 0.2s ease; +} +.service-stack-item:hover { + transform: translate(-2px, -2px); + box-shadow: 4px 4px 0 var(--ink); +} +.service-stack-num { + font: 900 24px/1 'JetBrains Mono', monospace; + color: var(--coral); + background: var(--brand-yellow); + border: 1.5px solid var(--ink); + padding: 6px 10px; + flex-shrink: 0; +} +.service-stack-icon { + font-size: 24px; + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + background: var(--paper-2); + border: 1.5px solid var(--ink); + flex-shrink: 0; +} +.service-stack-body { flex: 1; } +.service-stack-title { + font: 800 18px/1.3 'Kanit', sans-serif; + color: var(--ink); + margin: 0 0 8px; +} +.service-stack-bullets { + list-style: none; + padding: 0; + margin: 0; +} +.service-stack-bullets li { + font: 400 14px/1.5 'Kanit', sans-serif; + color: var(--text-dim); + padding: 4px 0; + display: grid; + grid-template-columns: 16px 1fr; + gap: 8px; +} +.service-stack-bullets li::before { + content: '▸'; + color: var(--coral); + font-weight: 700; +} + +/* ----- Portfolio card (custom grid variant on portfolio page) ----- */ +.portfolio-card-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px; +} +@media (max-width: 1024px) { .portfolio-card-grid { grid-template-columns: repeat(2, 1fr); } } +@media (max-width: 640px) { .portfolio-card-grid { grid-template-columns: 1fr; } } +.portfolio-card-top { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 12px; + background: var(--paper-2); + border-bottom: 1px solid var(--ink); + font: 700 9px/1 'JetBrains Mono', monospace; + text-transform: uppercase; +} +.portfolio-card-badge { + background: var(--coral); + color: #FAFAFA; + padding: 4px 8px; +} +.portfolio-card-arrow { color: var(--text-dim); } +.portfolio-card-name { + font: 800 20px/1.2 'Kanit', sans-serif; + color: var(--ink); + margin: 16px 0 4px; +} +.portfolio-card-industry { + font: 400 12px/1.3 'Kanit', sans-serif; + color: var(--text-dim); + margin-bottom: 8px; +} +.portfolio-card-highlight { + font: 700 11px/1.4 'JetBrains Mono', monospace; + color: var(--coral); +} + +/* ----- Contact form (legacy /contact page form) ----- */ +.contact-form { + display: flex; + flex-direction: column; + gap: 16px; + max-width: 600px; + margin: 0 auto; +} +.contact-form .form-group { display: flex; flex-direction: column; gap: 4px; } +.contact-form .form-label { + font: 600 13px/1 'Kanit', sans-serif; + color: var(--ink); +} +.contact-form .form-input { + font: 400 14px/1.4 'Kanit', sans-serif; + padding: 10px 12px; + border: 1.5px solid var(--ink); + background: var(--paper); + color: var(--ink); +} +.contact-form .form-input:focus { + outline: none; + border-color: var(--coral); + box-shadow: 2px 2px 0 var(--brand-yellow); +} +.contact-form .form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; +} +@media (max-width: 640px) { .contact-form .form-row { grid-template-columns: 1fr; } } +.contact-form .btn-submit { + background: var(--ink); + color: #FAFAFA; + border: 1.5px solid var(--ink); + padding: 12px 24px; + font: 800 12px/1 'JetBrains Mono', monospace; + text-transform: uppercase; + cursor: pointer; + transition: all 0.15s ease; + align-self: flex-start; +} +.contact-form .btn-submit:hover { + background: var(--coral); + border-color: var(--coral); + transform: translate(-2px, -2px); + box-shadow: 4px 4px 0 var(--brand-yellow); +} +.form-success { + background: var(--paper); + border: 2px solid var(--brand-yellow); + padding: 32px; + text-align: center; + max-width: 600px; + margin: 0 auto; +} +.form-success h3 { + font: 800 24px/1.2 'Kanit', sans-serif; + color: var(--ink); + margin: 16px 0 8px; +} +.form-success p { + font: 400 15px/1.5 'Kanit', sans-serif; + color: var(--text-dim); +} + +/* ----- Utility (inner-page helpers) ----- */ +.btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 12px 20px; + font: 800 12px/1 'JetBrains Mono', monospace; + text-transform: uppercase; + letter-spacing: 0.5px; + text-decoration: none; + border: 1.5px solid var(--ink); + cursor: pointer; + transition: all 0.15s ease; +} +.btn-primary { + background: var(--coral); + color: #FAFAFA; +} +.btn-primary:hover { + background: var(--ink); + color: var(--brand-yellow); + transform: translate(-2px, -2px); + box-shadow: 4px 4px 0 var(--coral); +} +.btn-outline-dark { + background: var(--paper); + color: var(--ink); +} +.btn-outline-dark:hover { + background: var(--brand-yellow); + transform: translate(-2px, -2px); + box-shadow: 4px 4px 0 var(--ink); +} +.info-icon { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + background: var(--paper-2); + border: 1.5px solid var(--ink); + margin-bottom: 12px; +} +.checklist { + list-style: none; + padding: 0; + margin: 0; +} +.checklist li { + font: 400 14px/1.6 'Kanit', sans-serif; + color: var(--ink); + padding: 8px 0; + border-bottom: 1px solid var(--line); +} + +/* ----- Filter bar (portfolio page) ----- */ +.filter-section { + background: var(--paper-2); + padding: 20px 0; + border-top: 1px solid var(--line-2); + border-bottom: 1px solid var(--line-2); + position: sticky; + top: 70px; + z-index: 50; +} +.filter-bar { + display: flex; + gap: 8px; + overflow-x: auto; + padding: 4px 0; +} +.filter-btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 12px 20px; + background: var(--paper); + color: var(--ink); + border: 1px solid var(--line-2); + border-radius: 999px; + font: 600 14px/1 'Kanit', sans-serif; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} +.filter-btn:hover { border-color: var(--coral); } +.filter-btn.active { + background: var(--brand-yellow); + border-color: var(--brand-yellow); + color: var(--ink); +} + +/* Dark mode overrides for legacy aliases ----- */ +html.dark .section-soft { background: var(--paper-2); } +html.dark .section-badge { background: var(--brand-yellow); color: var(--ink); } +html.dark .section-title { color: var(--ink); } +html.dark .info-icon { background: var(--paper-2); } +html.dark .filter-section { background: var(--paper-2); } +html.dark .filter-btn { background: var(--paper); color: var(--ink); } +html.dark .filter-btn.active { background: var(--brand-yellow); color: var(--ink); } +html.dark .contact-form .form-input { + background: var(--paper-2); + color: var(--ink); + border-color: var(--ink); +} +html.dark .service-stack-item { background: var(--paper); } +html.dark .form-success { background: var(--paper); } +html.dark .reveal { /* keep hidden state, light/dark mode just affects colors */ } + +/* ============================================ + BENTO COMPONENT ALIASES (added 2026-06-13) + Pages still use , , + components (in services/[slug], contact, faq, blog, + privacy, terms). These components emit divs with + classes like .bento-grid, .bento-tile, .surface-yellow, + .span-6 etc. We alias them to v6 design tokens so + the rendered output matches the rest of the site. + ============================================ */ + +/* BentoGrid: 12-col grid */ +.bento-grid { + display: grid; + grid-template-columns: repeat(12, 1fr); + grid-auto-rows: minmax(80px, auto); + gap: 16px; + position: relative; + max-width: 1200px; + margin: 0 auto; +} +@media (max-width: 1024px) { .bento-grid { grid-template-columns: repeat(6, 1fr); } } +@media (max-width: 640px) { .bento-grid { grid-template-columns: 1fr; gap: 12px; } } + +/* BentoTile: card with v6 surface treatments */ +.bento-tile { + padding: 24px; + background: var(--paper); + border: 1.5px solid var(--ink); + position: relative; + display: flex; + flex-direction: column; + gap: 12px; + transition: all 0.2s ease; + grid-column: span 6; +} +.bento-tile:hover { transform: translate(-2px, -2px); box-shadow: 4px 4px 0 var(--ink); } +@media (max-width: 640px) { .bento-tile { grid-column: span 1; } } + +/* Span variants */ +.bento-tile.span-3 { grid-column: span 3; } +.bento-tile.span-4 { grid-column: span 4; } +.bento-tile.span-5 { grid-column: span 5; } +.bento-tile.span-6 { grid-column: span 6; } +.bento-tile.span-7 { grid-column: span 7; } +.bento-tile.span-8 { grid-column: span 8; } +.bento-tile.span-12 { grid-column: span 12; } + +/* Rows variants */ +.bento-tile.rows-2 { grid-row: span 2; } +.bento-tile.rows-3 { grid-row: span 3; } + +/* Surface treatments (v6 design tokens) */ +.bento-tile.surface-white { background: var(--paper); color: var(--ink); } +.bento-tile.surface-soft { background: var(--paper-2); color: var(--ink); } +.bento-tile.surface-yellow { background: var(--brand-yellow); color: var(--ink); } +.bento-tile.surface-purple { background: #7c3aed; color: #FAFAFA; } +.bento-tile.surface-purple-soft { background: #ede9fe; color: var(--ink); } +.bento-tile.surface-teal { background: #0d9488; color: #FAFAFA; } +.bento-tile.surface-teal-soft { background: #bae6fd; color: var(--ink); } +.bento-tile.surface-mint { background: #10b981; color: #FAFAFA; } +.bento-tile.surface-dark { background: var(--ink); color: #FAFAFA; } +.bento-tile.surface-coral { background: var(--coral); color: #FAFAFA; } + +/* BentoTile child elements */ +.bento-tile .tile-eyebrow { + font: 700 10px/1 'JetBrains Mono', monospace; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--ink); + background: var(--brand-yellow); + border: 1.5px solid var(--ink); + padding: 6px 10px; + align-self: flex-start; +} +.bento-tile .tile-title { + font: 800 clamp(20px, 2.4vw, 28px)/1.2 'Kanit', sans-serif; + letter-spacing: -0.5px; + color: var(--ink); + margin: 0; +} +.bento-tile.surface-dark .tile-title, +.bento-tile.surface-coral .tile-title { color: #FAFAFA; } +.bento-tile .tile-body { flex: 1; } +.bento-tile .tile-body p { + font: 400 15px/1.6 'Kanit', sans-serif; + color: var(--ink); + margin: 0 0 12px; +} +.bento-tile.surface-dark .tile-body p, +.bento-tile.surface-coral .tile-body p { color: rgba(250,250,250,0.85); } +.bento-tile .tile-body ul { + list-style: none; + padding: 0; + margin: 0; +} +.bento-tile .tile-body li { + font: 400 14px/1.5 'Kanit', sans-serif; + color: var(--ink); + padding: 4px 0; + display: grid; + grid-template-columns: 16px 1fr; + gap: 8px; +} +.bento-tile.surface-dark .tile-body li, +.bento-tile.surface-coral .tile-body li { color: rgba(250,250,250,0.85); } +.bento-tile .tile-body li::before { content: '▸'; color: var(--coral); font-weight: 700; } + +/* BentoTile links/buttons inside */ +.bento-tile .tile-link { + font: 800 12px/1 'JetBrains Mono', monospace; + text-transform: uppercase; + color: var(--coral); + text-decoration: none; + align-self: flex-start; + margin-top: auto; + border-bottom: 2px solid var(--coral); + padding-bottom: 2px; +} +.bento-tile .tile-link:hover { color: var(--ink); border-color: var(--ink); } + +/* Tile mega-cta (if used) */ +.bento-tile .mega-cta { + background: var(--ink); + color: #FAFAFA; + padding: 10px 16px; + font: 800 11px/1 'JetBrains Mono', monospace; + text-transform: uppercase; + text-decoration: none; + align-self: flex-start; + margin-top: auto; +} +.bento-tile .mega-cta:hover { background: var(--coral); } + +/* Reveal animation (when BentoTile used) */ +.bento-tile.reveal { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; +} +.bento-tile.reveal.revealed { opacity: 1; transform: translateY(0); } + +/* Container class (legacy bento variant) */ +.bento-tile-container { + position: relative; + z-index: 1; + display: contents; +} + +/* Dark mode bento overrides */ +html.dark .bento-tile.surface-soft { background: var(--paper-2); color: var(--ink); } +html.dark .bento-tile.surface-purple-soft { background: rgba(124,58,237,0.18); color: var(--ink); } +html.dark .bento-tile.surface-yellow { color: var(--ink); } + /* 3 results the user positions the business around (เพิ่มยอดขาย / ลดต้นทุน / ประหยัดเวลา) */ .fx-hero-results { display: grid; @@ -708,6 +1256,7 @@ html.dark body { background: var(--body-bg); color: var(--body-fg); } .fx-hero-results { grid-template-columns: 1fr; } } + /* v7-5 uses rgba(10,10,10,0.3) for dim text (.ts in log + footer-bottom) Invert to cream-equivalent for dark mode */ html.dark .ts { color: rgba(250,250,250,0.3); }