@tokenoftrust/cli 1.3.4-rc.4 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/bin/tot.mjs +8 -0
  2. package/package.json +2 -1
  3. package/src/app-scaffold.mjs +84 -0
  4. package/src/banner.mjs +46 -0
  5. package/src/commands/app/dev.mjs +268 -0
  6. package/src/commands/app/index.mjs +35 -0
  7. package/src/commands/app/scaffold.mjs +57 -0
  8. package/src/commands/dev.mjs +57 -13
  9. package/src/commands/start.mjs +76 -17
  10. package/src/commands/validate.mjs +4 -0
  11. package/src/dev-logs.mjs +34 -7
  12. package/src/validate.mjs +77 -8
  13. package/src/vendor/private-apps-devkit.mjs +490 -0
  14. package/template/private-app/.env.example +10 -0
  15. package/template/private-app/Dockerfile +12 -0
  16. package/template/private-app/README.md +45 -0
  17. package/template/private-app/fixtures/order.created.cloudevent.json +36 -0
  18. package/template/private-app/server.js +81 -0
  19. package/template/private-app/tot-app.json +29 -0
  20. package/template/sample-store/content/chrome.html +140 -0
  21. package/template/sample-store/content/chrome.json +86 -0
  22. package/template/sample-store/content/home.html +121 -0
  23. package/template/sample-store/content/home.json +50 -0
  24. package/template/sample-store/content/pages/about.json +10 -0
  25. package/template/sample-store/content/pages/privacy.json +10 -0
  26. package/template/sample-store/content/pages/shipping-returns.json +10 -0
  27. package/template/sample-store/content/pages-html/blogs/news.html +26 -0
  28. package/template/sample-store/content/pages-html/pages/about-us.html +44 -0
  29. package/template/sample-store/content/pages-html/pages/contact-us.html +48 -0
  30. package/template/sample-store/content/pages-html/pages/privacy-policy.html +27 -0
  31. package/template/sample-store/content/pages-html/pages/shipping-returns.html +25 -0
  32. package/template/sample-store/public/logo.svg +6 -0
  33. package/template/sample-store/public/pages/home.css +120 -0
  34. package/template/sample-store/public/pages/mkt.css +185 -0
  35. package/template/sample-store/public/pages/page.css +155 -0
  36. package/template/sample-store/public/themes/sample.css +76 -0
  37. package/template/sample-store/theme.json +38 -0
@@ -0,0 +1,25 @@
1
+ <head>
2
+ <title>Shipping &amp; Returns | Sample Vapor Co.</title>
3
+ <meta name="description" content="Sample shipping and returns copy for the fictional Sample Vapor Co. demo store.">
4
+ <link rel="canonical" href="https://sample-store.example/pages/shipping-returns">
5
+ <meta name="robots" content="noindex,nofollow">
6
+ <link rel="stylesheet" href="/tenants/sample-store.example/pages/page.css">
7
+ </head>
8
+ <main id="main">
9
+ <section class="page-hero section--tight">
10
+ <div class="container">
11
+ <nav class="crumbs" aria-label="Breadcrumb"><a href="/">Home</a> / Shipping &amp; Returns</nav>
12
+ <span class="eyebrow">Sample content</span>
13
+ <h1>Shipping &amp; Returns</h1>
14
+ </div>
15
+ </section>
16
+ <section class="section">
17
+ <div class="container prose">
18
+ <p><em>Sample Vapor Co. is a fictional demo store. The text below is neutral placeholder copy, not a real shipping policy.</em></p>
19
+ <h2>Shipping</h2>
20
+ <p>Age-restricted products require an adult signature (21+) on delivery. Describe your real shipping methods and timelines here.</p>
21
+ <h2>Returns</h2>
22
+ <p>Describe your return policy here. Consumable nicotine products are commonly non-returnable — set your own terms.</p>
23
+ </div>
24
+ </section>
25
+ </main>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 48" width="240" height="48" role="img" aria-label="Sample Vapor Co.">
2
+ <rect width="240" height="48" rx="8" fill="#1b3b64"/>
3
+ <circle cx="26" cy="24" r="10" fill="none" stroke="#e0a83a" stroke-width="3"/>
4
+ <path d="M26 18v12M20 24h12" stroke="#e0a83a" stroke-width="3" stroke-linecap="round"/>
5
+ <text x="48" y="30" font-family="Montserrat, Inter, system-ui, sans-serif" font-size="18" font-weight="700" fill="#ffffff">Sample Vapor Co.</text>
6
+ </svg>
@@ -0,0 +1,120 @@
1
+ /* ============================================================================
2
+ Sample Vapor Co. — home page (fictional demo store, above-the-fold).
3
+ Section order + chrome mirror the live Shopify theme. Shared base in
4
+ themes/sample.css + pages/mkt.css.
5
+ ========================================================================== */
6
+
7
+ /* --- Hero: TWO-UP (banner + promo tile), no overlay text ------------------ */
8
+ .hero2 { padding-block: clamp(16px, 2vw, 24px); }
9
+ .hero2 .container { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; }
10
+ .hero2 a { display: block; border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm); }
11
+ .hero2 img { width: 100%; height: clamp(260px, 34vw, 420px); object-fit: cover; }
12
+ .hero2 .promo-tile { background: linear-gradient(135deg, #0b1020, var(--navy-ink)); }
13
+
14
+ /* --- 3 promo cards -------------------------------------------------------- */
15
+ .promos { padding-block: clamp(12px, 2vw, 20px); }
16
+ .promos .container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
17
+ .promo-card {
18
+ position: relative; min-height: 240px; border-radius: var(--radius-lg); overflow: hidden;
19
+ display: flex; flex-direction: column; justify-content: flex-start; padding: 28px; color: #fff;
20
+ }
21
+ .promo-card--blue { background: linear-gradient(160deg, #1466ff, var(--navy)); }
22
+ .promo-card--red { background: linear-gradient(160deg, #ff3b46, var(--sale)); }
23
+ .promo-card--img { background: #10131c; padding: 0; }
24
+ .promo-card--img img { width: 100%; height: 100%; object-fit: cover; }
25
+ .promo-card h3 { color: #fff; font-size: 1.7rem; }
26
+ .promo-card p { color: rgba(255,255,255,.88); margin-top: 4px; font-weight: 500; }
27
+ .promo-card .link { margin-top: 14px; font-family: var(--font-display); font-weight: 700; color: #fff; }
28
+ .promo-card .link::after { content: " ›"; }
29
+
30
+ /* --- Categories (icon cards, light-blue) ---------------------------------- */
31
+ .cats { padding-block: clamp(2rem, 4vw, 3.5rem); }
32
+ .cats h2 { text-align: center; margin-bottom: clamp(1.5rem, 3vw, 2.5rem); }
33
+ .cats .grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: clamp(12px, 1.6vw, 20px); }
34
+ .cat-icon-card {
35
+ display: flex; flex-direction: column; align-items: center; gap: 16px;
36
+ background: #fff; border: 1px solid var(--border); border-radius: var(--radius-lg);
37
+ padding: 26px 16px; text-align: center; transition: transform .14s, box-shadow .14s;
38
+ }
39
+ .cat-icon-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
40
+ .cat-icon-card .ico {
41
+ width: 92px; height: 92px; border-radius: 18px; background: var(--surface-2);
42
+ display: grid; place-items: center;
43
+ }
44
+ .cat-icon-card .ico svg { width: 52px; height: 52px; stroke: var(--navy); fill: none; stroke-width: 1.6; }
45
+ .cat-icon-card span { font-family: var(--font-display); font-weight: 700; color: var(--ink); }
46
+
47
+ /* --- Responsive ----------------------------------------------------------- */
48
+ @media (max-width: 900px) {
49
+ .hero2 .container { grid-template-columns: 1fr; }
50
+ .hero2 .promo-tile { display: none; }
51
+ .promos .container { grid-template-columns: 1fr; }
52
+ .cats .grid { grid-template-columns: repeat(3, 1fr); }
53
+ }
54
+ @media (max-width: 560px) {
55
+ .cats .grid { grid-template-columns: repeat(2, 1fr); }
56
+ }
57
+
58
+ /* --- Footer newsletter ---------------------------------------------------- */
59
+ .footer-news { display: flex; gap: 8px; margin-top: 12px; max-width: 320px; }
60
+ .footer-news input { flex: 1; border: 1px solid rgba(255,255,255,.3); background: transparent; color: #fff; border-radius: 999px; padding: 10px 16px; font-size: .9rem; }
61
+ .footer-news input::placeholder { color: #a9b8e6; }
62
+ .footer-news button { background: #fff; color: var(--navy-ink); border: 0; border-radius: 999px; width: 42px; font-size: 1.1rem; font-weight: 700; cursor: pointer; }
63
+ .footer-col > p { color: #a9b8e6; font-size: .88rem; margin-top: 4px; }
64
+
65
+ /* --- Payment badges ------------------------------------------------------- */
66
+ .pay-badges { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
67
+ .pay-badges span { background: #fff; color: var(--navy-ink); font-size: .62rem; font-weight: 800; letter-spacing: .03em; padding: 6px 9px; border-radius: 5px; }
68
+
69
+ /* --- Product carousel (real catalog snapshot) ----------------------------- */
70
+ .shelf .sec-head { margin-bottom: 1.25rem; }
71
+ .pcarousel {
72
+ display: grid; grid-auto-flow: column; grid-auto-columns: minmax(200px, 1fr);
73
+ gap: clamp(12px, 1.6vw, 20px); overflow-x: auto; scroll-snap-type: x mandatory;
74
+ padding-bottom: 12px; scrollbar-width: thin;
75
+ }
76
+ .pcard { scroll-snap-align: start; }
77
+ .pcard a { display: block; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; transition: transform .14s, box-shadow .14s, border-color .14s; }
78
+ .pcard a:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--surface-2); }
79
+ .pcard__media { aspect-ratio: 1/1; background: var(--surface); display: grid; place-items: center; }
80
+ .pcard__media img { width: 100%; height: 100%; object-fit: contain; padding: 10px; }
81
+ .pcard__vendor { font-family: var(--font-display); font-size: .68rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); padding: 12px 14px 0; }
82
+ .pcard__title { font-family: var(--font-body); font-size: .9rem; font-weight: 600; line-height: 1.3; color: var(--ink); padding: 2px 14px 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
83
+ .pcard__price { font-family: var(--font-display); font-weight: 700; color: var(--navy); padding: 6px 14px 14px; }
84
+ .pcard__was { color: var(--muted); font-weight: 500; text-decoration: line-through; margin-right: 4px; }
85
+
86
+ /* --- Staff's Pick spotlight ----------------------------------------------- */
87
+ .spotlight { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 4vw, 48px); align-items: center; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; }
88
+ .spotlight:hover { box-shadow: var(--shadow-md); }
89
+ .spotlight__media { aspect-ratio: 4/3; background: var(--surface); display: grid; place-items: center; }
90
+ .spotlight__media img { width: 100%; height: 100%; object-fit: contain; padding: 24px; }
91
+ .spotlight__body { padding: clamp(20px, 4vw, 40px) clamp(20px, 4vw, 40px) clamp(20px, 4vw, 40px) 0; }
92
+ .spotlight__body h3 { font-size: clamp(1.3rem, 2.6vw, 1.9rem); margin: 4px 0 10px; }
93
+ .spotlight__price { font-family: var(--font-display); font-weight: 700; font-size: 1.3rem; color: var(--navy); margin-bottom: 1.2rem; }
94
+
95
+ /* --- Shop by Brands grid -------------------------------------------------- */
96
+ .brandgrid { display: grid; grid-template-columns: repeat(6, 1fr); gap: clamp(10px, 1.4vw, 16px); }
97
+ .brandtile { display: grid; place-items: center; background: #fff; border: 1px solid var(--border); border-radius: var(--radius); min-height: 96px; padding: 14px; transition: transform .14s, box-shadow .14s, border-color .14s; }
98
+ .brandtile:hover { transform: translateY(-3px); box-shadow: var(--shadow-sm); border-color: var(--surface-2); }
99
+ .brandtile img { max-height: 56px; max-width: 100%; object-fit: contain; }
100
+ /* Text brand tile (used when a brand has no logo asset) — same tile chrome, name centered. */
101
+ .brandtile--text { font-family: var(--font-display); font-weight: 700; color: var(--navy); text-align: center; font-size: .95rem; letter-spacing: -.01em; }
102
+
103
+ /* --- Blog cards ----------------------------------------------------------- */
104
+ .bloggrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(14px, 2vw, 24px); }
105
+ .blogcard { display: flex; flex-direction: column; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; transition: transform .14s, box-shadow .14s; }
106
+ .blogcard:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
107
+ .blogcard__media { aspect-ratio: 16/9; background: linear-gradient(135deg, var(--surface-2), var(--surface)); }
108
+ .blogcard h3 { font-size: 1.02rem; line-height: 1.35; padding: 16px 18px 0; color: var(--ink); }
109
+ .blogcard .link-more { padding: 10px 18px 18px; }
110
+
111
+ .center { text-align: center; }
112
+
113
+ @media (max-width: 900px) {
114
+ .spotlight { grid-template-columns: 1fr; }
115
+ .spotlight__media { aspect-ratio: 16/10; }
116
+ .spotlight__body { padding: 0 24px 28px; }
117
+ .brandgrid { grid-template-columns: repeat(4, 1fr); }
118
+ .bloggrid { grid-template-columns: 1fr; }
119
+ }
120
+ @media (max-width: 560px) { .brandgrid { grid-template-columns: repeat(3, 1fr); } }
@@ -0,0 +1,185 @@
1
+ /* ============================================================================
2
+ Sample Vapor Co. — shared marketing component layer (mkt.css)
3
+ Reused across home + all marketing pages: layout, buttons, header/nav,
4
+ footer, section headers, tile + category grids, compliance strip.
5
+ Depends on tokens from themes/sample.css.
6
+ ========================================================================== */
7
+
8
+ /* --- Layout --------------------------------------------------------------- */
9
+ .container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: clamp(16px, 4vw, 40px); }
10
+ .section { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
11
+ .section--tight { padding-block: clamp(1.75rem, 4vw, 3rem); }
12
+ .section--surface { background: var(--surface); }
13
+
14
+ /* --- Buttons -------------------------------------------------------------- */
15
+ .btn {
16
+ display: inline-flex; align-items: center; justify-content: center; gap: .5em;
17
+ font-family: var(--font-display); font-weight: 600; font-size: .95rem;
18
+ padding: .8em 1.6em; border-radius: 999px; border: 2px solid transparent;
19
+ transition: transform .12s ease, background .15s ease, color .15s ease, box-shadow .15s ease;
20
+ }
21
+ .btn:hover { transform: translateY(-1px); }
22
+ .btn-primary { background: var(--navy); color: #fff; }
23
+ .btn-primary:hover { background: var(--navy-dark); box-shadow: var(--shadow-md); }
24
+ .btn-line { border-color: #fff; color: #fff; }
25
+ .btn-line:hover { background: #fff; color: var(--navy); }
26
+ .btn-ghost { border-color: var(--border); color: var(--navy); background: #fff; }
27
+ .btn-ghost:hover { border-color: var(--navy); }
28
+
29
+ /* --- Announcement bar ----------------------------------------------------- */
30
+ .announce {
31
+ background: var(--navy); color: #fff; text-align: center;
32
+ font-size: .85rem; font-weight: 600; letter-spacing: .01em; padding: 9px 16px;
33
+ }
34
+
35
+ /* --- Top utility bar (shared chrome: FDA warning + marquee + utility nav) -- */
36
+ .topbar-warning {
37
+ background: #fff; border-bottom: 1px solid var(--border);
38
+ text-align: center; padding: 10px 16px;
39
+ }
40
+ .topbar-warning p { color: var(--ink); font-weight: 700; font-size: .82rem; letter-spacing: .01em; }
41
+
42
+ .announce-marquee { background: var(--sale); color: #fff; overflow: hidden; }
43
+ .announce-marquee__track {
44
+ display: flex; gap: 3rem; white-space: nowrap; width: max-content;
45
+ padding: 8px 0; font-size: .82rem; font-weight: 600;
46
+ animation: bdv-marquee 22s linear infinite;
47
+ }
48
+ .announce-marquee__track span { padding-inline: 1.5rem; }
49
+ @keyframes bdv-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
50
+ @media (prefers-reduced-motion: reduce) {
51
+ .announce-marquee__track { animation: none; justify-content: center; width: 100%; }
52
+ }
53
+
54
+ .utility-nav { border-bottom: 1px solid var(--border); background: #fff; }
55
+ .utility-nav .container { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding-block: 8px; }
56
+ .utility-nav ul { display: flex; gap: 20px; }
57
+ .utility-nav a { font-size: .82rem; font-weight: 600; color: var(--ink); }
58
+ .utility-nav a:hover { color: var(--navy); }
59
+ .utility-nav__right { display: flex; align-items: center; gap: 16px; }
60
+ .utility-nav__right .sel { font-size: .8rem; color: var(--muted); }
61
+ .utility-nav__right .social { display: flex; gap: 12px; }
62
+ .utility-nav__right .social a svg { width: 16px; height: 16px; fill: var(--ink); }
63
+
64
+ /* --- Header / nav --------------------------------------------------------- */
65
+ .site-header { position: sticky; top: 0; z-index: 100; background: #fff; border-bottom: 1px solid var(--border); }
66
+ .header-row { display: flex; align-items: center; gap: clamp(12px, 2.5vw, 32px); padding-block: 14px; }
67
+ .brand img { height: 46px; width: auto; }
68
+ .primary-nav { flex: 1; }
69
+ .primary-nav > ul { display: flex; flex-wrap: wrap; align-items: center; gap: clamp(10px, 1.6vw, 22px); }
70
+ .primary-nav a { font-weight: 600; font-size: .92rem; color: var(--ink); padding: 6px 2px; border-bottom: 2px solid transparent; transition: color .15s, border-color .15s; }
71
+ .primary-nav a:hover { color: var(--navy); border-color: var(--navy); }
72
+ .primary-nav a.is-flag { color: var(--sale); }
73
+ .header-actions { display: flex; align-items: center; gap: 16px; }
74
+ .header-actions a { display: inline-flex; color: var(--ink); }
75
+ .header-actions a:hover { color: var(--navy); }
76
+ .header-actions svg { width: 24px; height: 24px; stroke: currentColor; fill: none; stroke-width: 1.8; }
77
+ .hamburger { display: none; flex-direction: column; gap: 5px; background: none; border: 0; padding: 6px; }
78
+ .hamburger span { width: 26px; height: 2px; background: var(--ink); border-radius: 2px; }
79
+
80
+ /* header search pill + account/cart badge (shared chrome) */
81
+ .site-header .header-row { gap: clamp(12px, 3vw, 40px); }
82
+ .header-search { flex: 1; max-width: 560px; position: relative; }
83
+ .header-search input {
84
+ width: 100%; border: 1px solid var(--border); border-radius: 999px;
85
+ padding: 11px 46px 11px 18px; font-size: .9rem; background: #fff; color: var(--ink);
86
+ }
87
+ .header-search input::placeholder { color: var(--muted); }
88
+ .header-search button { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); background: none; border: 0; padding: 6px; }
89
+ .header-search svg { width: 20px; height: 20px; stroke: var(--navy); fill: none; stroke-width: 2; }
90
+ .header-actions .cart { position: relative; }
91
+ .header-actions .cart .count {
92
+ position: absolute; top: -6px; right: -8px; background: var(--navy); color: #fff;
93
+ font-size: .62rem; font-weight: 700; min-width: 16px; height: 16px; border-radius: 999px;
94
+ display: grid; place-items: center; padding: 0 4px;
95
+ }
96
+
97
+ /* primary nav: NEW badge + dropdown carets + second-row nav bar (shared chrome) */
98
+ .primary-nav a .new-badge {
99
+ display: inline-block; background: var(--sale); color: #fff; font-size: .58rem; font-weight: 800;
100
+ letter-spacing: .06em; padding: 2px 5px; border-radius: 4px; margin-left: 6px; vertical-align: middle;
101
+ }
102
+ .primary-nav a .caret { font-size: .7em; margin-left: 4px; opacity: .7; }
103
+ .primary-nav-bar { border-top: 1px solid var(--border); background: #fff; }
104
+ .primary-nav-bar .container { padding-block: 4px; }
105
+ .primary-nav-bar .primary-nav > ul { gap: clamp(10px, 1.4vw, 20px); }
106
+ .primary-nav-bar .primary-nav a { padding-block: 10px; }
107
+
108
+ /* --- Section headers ------------------------------------------------------ */
109
+ .sec-head { text-align: center; max-width: 62ch; margin: 0 auto clamp(1.5rem, 3vw, 2.5rem); }
110
+ .sec-head .eyebrow { display: inline-block; font-family: var(--font-display); font-weight: 700; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; color: var(--navy); margin-bottom: .55rem; }
111
+ .sec-head p { margin-top: .7rem; font-size: 1.02rem; }
112
+ .sec-head--between { display: flex; align-items: baseline; justify-content: space-between; text-align: left; max-width: none; gap: 16px; }
113
+ .link-more { font-family: var(--font-display); font-weight: 600; color: var(--navy); white-space: nowrap; }
114
+ .link-more:hover { text-decoration: underline; }
115
+
116
+ /* --- Brand / category tile grid ------------------------------------------- */
117
+ .tile-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(12px, 1.6vw, 20px); }
118
+ .tile {
119
+ display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
120
+ background: #fff; border: 1px solid var(--border); border-radius: var(--radius-lg);
121
+ padding: 26px 18px; min-height: 148px; text-align: center; transition: transform .14s, box-shadow .14s, border-color .14s;
122
+ }
123
+ .tile:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--surface-2); }
124
+ .tile img { max-height: 66px; width: auto; object-fit: contain; }
125
+ .tile span { font-family: var(--font-display); font-weight: 600; font-size: .95rem; color: var(--ink); }
126
+
127
+ /* --- Category cards (shop by category) ------------------------------------ */
128
+ .cat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(14px, 2vw, 24px); }
129
+ .cat-card {
130
+ position: relative; display: flex; align-items: flex-end; overflow: hidden;
131
+ min-height: 190px; border-radius: var(--radius-lg); color: #fff;
132
+ background: linear-gradient(135deg, var(--navy), var(--navy-ink));
133
+ padding: 22px; transition: transform .14s, box-shadow .14s;
134
+ }
135
+ .cat-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
136
+ .cat-card::after { content: "→"; position: absolute; top: 20px; right: 22px; font-size: 1.3rem; opacity: .85; }
137
+ .cat-card h3 { color: #fff; font-size: 1.35rem; }
138
+ .cat-card p { color: rgba(255, 255, 255, .82); margin-top: 4px; font-size: .9rem; }
139
+
140
+ /* --- Compliance strip (source-copied legal text; not fabricated) ---------- */
141
+ .compliance-strip { background: var(--surface-2); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
142
+ .compliance-strip .container { padding-block: 14px; }
143
+ .compliance-strip p { color: var(--navy-ink); font-size: .82rem; font-weight: 600; text-align: center; letter-spacing: .01em; }
144
+
145
+ /* --- Footer --------------------------------------------------------------- */
146
+ .site-footer { background: var(--navy-ink); color: #dbe4fb; padding-block: clamp(2.5rem, 5vw, 4rem) 1.5rem; }
147
+ .footer-grid { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: clamp(24px, 4vw, 56px); }
148
+ .footer-brand img { height: 40px; filter: brightness(0) invert(1); opacity: .95; }
149
+ .footer-brand p { color: #a9b8e6; margin-top: 14px; font-size: .9rem; max-width: 34ch; }
150
+ .footer-col h4 { color: #fff; font-size: .82rem; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 14px; }
151
+ .footer-col ul { display: flex; flex-direction: column; gap: 9px; }
152
+ .footer-col a { color: #c3cff0; font-size: .92rem; }
153
+ .footer-col a:hover { color: #fff; text-decoration: underline; }
154
+ .footer-warning { margin-top: 34px; padding: 16px 18px; border: 1px solid rgba(255, 255, 255, .22); border-radius: var(--radius); }
155
+ .footer-warning strong { color: #fff; }
156
+ .footer-warning p { color: #c3cff0; font-size: .82rem; }
157
+ .footer-bottom { margin-top: 28px; padding-top: 18px; border-top: 1px solid rgba(255, 255, 255, .16); display: flex; flex-wrap: wrap; gap: 10px 24px; justify-content: space-between; align-items: center; }
158
+ .footer-bottom p, .footer-bottom a { color: #93a4d6; font-size: .82rem; }
159
+
160
+ /* --- Reveal-on-scroll ----------------------------------------------------- */
161
+ .reveal { opacity: 0; transform: translateY(18px); transition: opacity .5s ease, transform .5s ease; }
162
+ .reveal.in { opacity: 1; transform: none; }
163
+
164
+ /* --- Responsive ----------------------------------------------------------- */
165
+ @media (max-width: 900px) {
166
+ .header-search { order: 3; flex-basis: 100%; max-width: none; }
167
+ .utility-nav ul { gap: 12px; }
168
+ }
169
+ @media (max-width: 1000px) {
170
+ .tile-grid { grid-template-columns: repeat(3, 1fr); }
171
+ }
172
+ @media (max-width: 860px) {
173
+ .primary-nav { position: fixed; inset: 0 0 0 auto; width: min(80vw, 320px); background: #fff; box-shadow: var(--shadow-lg); transform: translateX(100%); transition: transform .25s ease; padding: 80px 24px 24px; overflow-y: auto; }
174
+ .primary-nav.open { transform: none; }
175
+ .primary-nav > ul { flex-direction: column; align-items: stretch; gap: 4px; }
176
+ .primary-nav a { display: block; padding: 12px 4px; border-bottom: 1px solid var(--border); }
177
+ .hamburger { display: flex; }
178
+ .cat-grid { grid-template-columns: 1fr 1fr; }
179
+ .footer-grid { grid-template-columns: 1fr 1fr; }
180
+ }
181
+ @media (max-width: 560px) {
182
+ .tile-grid { grid-template-columns: repeat(2, 1fr); }
183
+ .cat-grid { grid-template-columns: 1fr; }
184
+ .footer-grid { grid-template-columns: 1fr; }
185
+ }
@@ -0,0 +1,155 @@
1
+ /* ============================================================================
2
+ Sample Vapor Co. — shared marketing subpage styles (page.css)
3
+ Page hero + prose + contact cards. Used by pages-html/**. Depends on tokens
4
+ from themes/sample.css and components from pages/mkt.css.
5
+ ========================================================================== */
6
+
7
+ /* --- Page hero ------------------------------------------------------------ */
8
+ .page-hero { background: linear-gradient(135deg, var(--navy), var(--navy-ink)); color: #fff; }
9
+ .page-hero .container { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
10
+ .page-hero .eyebrow { display: inline-block; font-family: var(--font-display); font-weight: 700; font-size: .78rem; letter-spacing: .14em; text-transform: uppercase; color: #afc2ff; margin-bottom: .7rem; }
11
+ .page-hero h1 { color: #fff; max-width: 22ch; }
12
+ .page-hero p { color: #dce5ff; font-size: 1.08rem; margin-top: .9rem; max-width: 60ch; }
13
+ .crumbs { font-size: .82rem; color: #a9b8e6; margin-bottom: 1rem; }
14
+ .crumbs a:hover { color: #fff; text-decoration: underline; }
15
+
16
+ /* --- Prose ---------------------------------------------------------------- */
17
+ .prose { max-width: 70ch; margin-inline: auto; }
18
+ .prose h2 { margin-top: 2.2rem; margin-bottom: .6rem; }
19
+ .prose h3 { margin-top: 1.6rem; margin-bottom: .4rem; }
20
+ .prose p { margin-bottom: 1rem; color: var(--ink); }
21
+ .prose p.lead { font-size: 1.15rem; color: var(--muted); }
22
+ .prose ul.bullets { margin: 0 0 1rem; padding-left: 1.1rem; list-style: disc; }
23
+ .prose ul.bullets li { margin-bottom: .4rem; color: var(--ink); }
24
+ .prose a { color: var(--navy); font-weight: 600; }
25
+ .prose a:hover { text-decoration: underline; }
26
+
27
+ /* --- Value cards (about-page "what we're about" grid) --------------------- */
28
+ .value-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(14px, 2vw, 22px); margin-top: 1.6rem; }
29
+ .value-card { border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 24px; background: #fff; }
30
+ .value-card h3 { color: var(--navy); font-size: 1.05rem; margin-bottom: .55rem; }
31
+ .value-card p { color: var(--ink); font-size: .96rem; }
32
+ @media (max-width: 860px) { .value-grid { grid-template-columns: 1fr; } }
33
+
34
+ /* --- Contact cards -------------------------------------------------------- */
35
+ .contact-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(14px, 2vw, 22px); margin-top: 1.5rem; }
36
+ .contact-card { border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 24px; background: #fff; }
37
+ .contact-card h3 { color: var(--navy); font-size: 1.05rem; margin-bottom: .5rem; }
38
+ .contact-card a { color: var(--ink); font-weight: 600; }
39
+ .contact-card a:hover { color: var(--navy); }
40
+ .contact-card p { font-size: .92rem; }
41
+
42
+ /* --- Brand chips ---------------------------------------------------------- */
43
+ .brand-chips { display: flex; flex-wrap: wrap; gap: 10px; margin: 1rem 0 1.5rem; }
44
+ .brand-chips a { border: 1px solid var(--border); border-radius: 999px; padding: 8px 16px; font-size: .88rem; font-weight: 600; color: var(--navy); background: var(--surface); }
45
+ .brand-chips a:hover { background: var(--surface-2); }
46
+
47
+ @media (max-width: 720px) {
48
+ .contact-grid { grid-template-columns: 1fr; }
49
+ }
50
+
51
+ /* ============================================================================
52
+ About page — hero overlay + alternating media/copy splits + pickers
53
+ (clones sample-store.example/pages/about-us section-for-section)
54
+ ========================================================================== */
55
+
56
+ /* --- Full-bleed hero with image + left-aligned overlay copy --------------- */
57
+ .hero-overlay { position: relative; overflow: hidden; background: var(--navy-ink); }
58
+ .hero-overlay > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
59
+ .hero-overlay::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, rgba(0,10,40,.62) 0%, rgba(0,10,40,.34) 45%, rgba(0,10,40,.08) 100%); }
60
+ .hero-overlay__inner { position: relative; z-index: 1; padding-block: clamp(3rem, 9vw, 7rem); }
61
+ .hero-overlay .crumbs { color: #cdd8f5; }
62
+ .hero-overlay .crumbs a { color: #eaf0ff; }
63
+ .hero-overlay h1 { color: #fff; max-width: 16ch; text-shadow: 0 2px 18px rgba(0,10,40,.4); }
64
+ .hero-overlay p { color: #eaf0ff; font-size: clamp(1rem, 1.6vw, 1.2rem); margin-top: 1rem; max-width: 46ch; }
65
+
66
+ /* --- Media / copy split (Our Story, Our Mission, Service) ------------------ */
67
+ .split .container { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.75rem, 5vw, 4.5rem); align-items: center; }
68
+ .split--rev .container { direction: rtl; }
69
+ .split--rev .split__copy, .split--rev .split__media { direction: ltr; }
70
+ .split__copy h2 { margin-bottom: 1rem; }
71
+ .split__copy p { color: var(--ink); margin-bottom: 1rem; max-width: 52ch; }
72
+ .split__copy .btn { margin-top: .4rem; }
73
+ .split__media img { width: 100%; border-radius: var(--radius-lg); box-shadow: var(--shadow-md); object-fit: cover; }
74
+ .split--center .split__copy { text-align: center; }
75
+ .split--center .split__copy p { margin-inline: auto; }
76
+ .split--center .split__copy .btn { display: inline-flex; }
77
+
78
+ /* --- Trusted Brands band (centered) --------------------------------------- */
79
+ .brands-band .brand-chips { justify-content: center; max-width: 780px; margin-inline: auto; }
80
+
81
+ /* --- Centered CTA band (Service — decorative image absent from source) ----- */
82
+ .cta-band { text-align: center; }
83
+ .cta-band .container { max-width: 60ch; }
84
+ .cta-band p { color: var(--ink); margin-top: 1rem; }
85
+ .cta-band .btn { margin-top: 1.5rem; }
86
+
87
+ /* --- Category picker (Find Your Fav) -------------------------------------- */
88
+ .pick-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(12px, 1.6vw, 20px); }
89
+ .pick-card {
90
+ display: flex; flex-direction: column; justify-content: space-between; gap: 12px;
91
+ min-height: 132px; padding: 22px 20px; background: #fff;
92
+ border: 1px solid var(--border); border-radius: var(--radius-lg);
93
+ transition: transform .14s, box-shadow .14s, border-color .14s;
94
+ }
95
+ .pick-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--surface-2); }
96
+ .pick-card h3 { color: var(--navy); font-size: 1.15rem; }
97
+ .pick-card span { font-family: var(--font-display); font-weight: 600; font-size: .9rem; color: var(--navy); }
98
+ .pick-card span::after { content: " →"; }
99
+
100
+ /* ============================================================================
101
+ Contact page — icon info band + form (clones /pages/contact-us)
102
+ ========================================================================== */
103
+ .page-hero--center { text-align: center; background: none; color: inherit; }
104
+ .page-hero--center h1 { color: var(--ink); max-width: none; margin-inline: auto; }
105
+ .page-hero--center p { color: var(--muted); margin-inline: auto; }
106
+
107
+ .contact-band { background: var(--navy); border-radius: var(--radius-lg); color: #fff; }
108
+ .contact-band .contact-band__inner { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(16px, 3vw, 32px); padding: clamp(28px, 5vw, 48px); text-align: center; }
109
+ .contact-band__item svg { width: 40px; height: 40px; margin: 0 auto 16px; stroke: #fff; fill: none; stroke-width: 1.6; }
110
+ .contact-band__item a, .contact-band__item span { color: #fff; font-size: 1.02rem; font-weight: 500; }
111
+ .contact-band__item a:hover { text-decoration: underline; }
112
+
113
+ .contact-form { margin-top: clamp(1.75rem, 4vw, 2.75rem); display: grid; gap: 16px; }
114
+ .contact-form .row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
115
+ .contact-form input, .contact-form textarea {
116
+ width: 100%; font: inherit; color: var(--ink); background: var(--surface);
117
+ border: 1px solid var(--border); border-radius: var(--radius); padding: 15px 18px;
118
+ }
119
+ .contact-form textarea { min-height: 180px; resize: vertical; }
120
+ .contact-form input::placeholder, .contact-form textarea::placeholder { color: var(--muted); }
121
+ .contact-form input:focus, .contact-form textarea:focus { outline: none; border-color: var(--navy); box-shadow: 0 0 0 3px rgba(0,48,160,.14); }
122
+ .contact-form .btn-primary { width: 100%; padding-block: 1em; font-size: 1rem; }
123
+
124
+ /* ============================================================================
125
+ Blog index — post-card grid (clones /blogs/news "Latest News")
126
+ ========================================================================== */
127
+ .blog-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(16px, 2.4vw, 28px); }
128
+ .blog-card {
129
+ display: flex; flex-direction: column; gap: 10px; padding: 24px;
130
+ background: #fff; border: 1px solid var(--border); border-radius: var(--radius-lg);
131
+ transition: transform .14s, box-shadow .14s, border-color .14s;
132
+ }
133
+ .blog-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--surface-2); }
134
+ .blog-card__date { font-size: .8rem; color: var(--muted); font-weight: 600; letter-spacing: .02em; }
135
+ .blog-card h2 { font-size: 1.18rem; line-height: 1.25; color: var(--ink); }
136
+ .blog-card h2 a:hover { color: var(--navy); }
137
+ .blog-card__more { margin-top: auto; font-family: var(--font-display); font-weight: 600; color: var(--navy); font-size: .9rem; }
138
+ .blog-card__more:hover { text-decoration: underline; }
139
+ .blog-card__more::after { content: " →"; }
140
+
141
+ /* --- Responsive ----------------------------------------------------------- */
142
+ @media (max-width: 900px) {
143
+ .pick-grid { grid-template-columns: repeat(2, 1fr); }
144
+ .blog-grid { grid-template-columns: repeat(2, 1fr); }
145
+ }
146
+ @media (max-width: 760px) {
147
+ .split .container, .split--rev .container { grid-template-columns: 1fr; direction: ltr; }
148
+ .split--rev .split__media { order: -1; }
149
+ .contact-band .contact-band__inner { grid-template-columns: 1fr; }
150
+ .contact-form .row2 { grid-template-columns: 1fr; }
151
+ }
152
+ @media (max-width: 560px) {
153
+ .pick-grid { grid-template-columns: 1fr 1fr; }
154
+ .blog-grid { grid-template-columns: 1fr; }
155
+ }
@@ -0,0 +1,76 @@
1
+ /* ============================================================================
2
+ Sample Vapor Co. — "sample" theme (swappable token + base layer)
3
+ A fictional store used only to demo the local dev loop. Deep navy on white
4
+ with a warm gold accent. This file is the reskinnable layer: design tokens,
5
+ reset, and base element styles. Shared components live in pages/mkt.css;
6
+ home-only in pages/home.css. Token values mirror theme.json.
7
+ ========================================================================== */
8
+
9
+ /* --- Design tokens -------------------------------------------------------- */
10
+ :root {
11
+ --navy: #1b3b64;
12
+ --navy-dark: #142d4d;
13
+ --navy-ink: #0f2138;
14
+ --ink: #16243d;
15
+ --muted: #5b6a82;
16
+ --bg: #ffffff;
17
+ --surface: #f5f7fa;
18
+ --surface-2: #eaeef4;
19
+ --border: #e3e8ef;
20
+ --gold: #e0a83a;
21
+ --gold-dark: #c8901f;
22
+ --sale: #8a5d10;
23
+ --ok: #2f8a5b;
24
+
25
+ --radius-sm: 6px;
26
+ --radius: 10px;
27
+ --radius-lg: 16px;
28
+ --shadow-sm: 0 1px 2px rgba(15, 33, 56, .06), 0 1px 3px rgba(15, 33, 56, .08);
29
+ --shadow-md: 0 6px 18px rgba(15, 33, 56, .10);
30
+ --shadow-lg: 0 18px 48px rgba(15, 33, 56, .16);
31
+
32
+ --container: 1240px;
33
+ --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
34
+ --font-display: "Montserrat", var(--font-body);
35
+ }
36
+
37
+ /* --- Reset ---------------------------------------------------------------- */
38
+ *, *::before, *::after { box-sizing: border-box; }
39
+ * { margin: 0; }
40
+ html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
41
+ body {
42
+ font-family: var(--font-body);
43
+ color: var(--ink);
44
+ background: var(--bg);
45
+ line-height: 1.55;
46
+ -webkit-font-smoothing: antialiased;
47
+ text-rendering: optimizeLegibility;
48
+ }
49
+ img, svg, video { display: block; max-width: 100%; height: auto; }
50
+ a { color: inherit; text-decoration: none; }
51
+ button { font: inherit; cursor: pointer; }
52
+ ul { list-style: none; padding: 0; }
53
+
54
+ /* --- Base typography ------------------------------------------------------ */
55
+ h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 700; line-height: 1.12; color: var(--ink); letter-spacing: -.01em; }
56
+ h1 { font-size: clamp(2rem, 4.6vw, 3.15rem); }
57
+ h2 { font-size: clamp(1.6rem, 3.2vw, 2.35rem); }
58
+ h3 { font-size: 1.2rem; }
59
+ p { color: var(--muted); }
60
+
61
+ /* --- Accessibility -------------------------------------------------------- */
62
+ :focus-visible { outline: 3px solid var(--navy); outline-offset: 2px; border-radius: 4px; }
63
+ .skip-link {
64
+ position: absolute; left: 8px; top: -48px; z-index: 200;
65
+ background: var(--navy); color: #fff; padding: 10px 16px; border-radius: 0 0 8px 8px;
66
+ transition: top .15s ease;
67
+ }
68
+ .skip-link:focus { top: 0; }
69
+ .sr-only {
70
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
71
+ overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
72
+ }
73
+ @media (prefers-reduced-motion: reduce) {
74
+ html { scroll-behavior: auto; }
75
+ *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
76
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "_vendor": "Sample Vapor Co.",
3
+ "_note": "Per-vendor theme override (DeepPartial<ThemeTokens>) for the FICTIONAL sample store shipped with the local dev loop. Matched from sample-store.example. Not a real merchant — neutral demo values only.",
4
+ "color": {
5
+ "bg": "#ffffff",
6
+ "surface": "#f5f7fa",
7
+ "text": "#16243d",
8
+ "muted": "#5b6a82",
9
+ "primary": "#1b3b64",
10
+ "primary-contrast": "#ffffff",
11
+ "accent": "#e0a83a",
12
+ "border": "#e3e8ef",
13
+ "success": "#2f8a5b",
14
+ "sale": "#8a5d10"
15
+ },
16
+ "type": {
17
+ "display": {
18
+ "family": "Montserrat",
19
+ "weights": [
20
+ 600,
21
+ 700,
22
+ 800
23
+ ]
24
+ },
25
+ "body": {
26
+ "family": "Inter",
27
+ "weights": [
28
+ 400,
29
+ 500,
30
+ 600
31
+ ]
32
+ }
33
+ },
34
+ "brand": {
35
+ "logoLight": "/tenants/sample-store.example/logo.svg",
36
+ "headerVariant": "dark"
37
+ }
38
+ }