@okjt/site 0.1.0 → 0.2.0

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.
package/README.md CHANGED
@@ -107,7 +107,7 @@ Any path not in `seo.pages` (and not resolved) gets the defaults and `noindex`.
107
107
  | `Container`, `Logo`, `PillLink`, `Eyebrow`, `Chip`, `SectionHeading` | Page width, the brand mark, call-to-action links, labels, headings |
108
108
  | `PhotoHero`, `HeroOrnament` | A full-bleed photo hero with a large light headline |
109
109
  | `ImageCard` | A large rounded card with a photo behind its words; a link when given `to` |
110
- | `Photo` | A photo filling its parent; a list of keys cross-fades |
110
+ | `Photo` | A photo filling its parent; a list of keys cross-fades. While loading or if it fails, a warm gradient shows (restyle it with `.okjt-photo`) |
111
111
  | `MediaFrame`, `MediaFill` | A product screen or clip in a browser or phone frame, or bare |
112
112
  | `FeatureExplorer` | Feature groups as tabs beside a large photo card with a summary, numbers and a screen |
113
113
  | `FeatureGroup` | One feature group in depth: heading, numbers, photo card and screen, every tool |
@@ -119,5 +119,18 @@ Any path not in `seo.pages` (and not resolved) gets the defaults and `noindex`.
119
119
  | `LegalPage` | A legal document with its contents beside it |
120
120
  | `RollingWord`, `useRolling` | Words that roll through a list in a headline |
121
121
 
122
+ Dark public pages: swap the theme's light and dark tokens and set `surface`,
123
+ `onInk` and `panel` (see `packages/UPGRADING.md`, site 0.2.0).
124
+
125
+ Class hooks for a project's CSS: `.okjt-site` (the page behind everything,
126
+ e.g. a gradient or texture), `.okjt-card-shade` (the shade over photos on
127
+ ImageCard and FeatureExplorer, e.g. darker for contrast), `.okjt-photo`
128
+ (a photo's loading or failed state), `.okjt-card` (cards on the page: the
129
+ explorer's summary, questions, a legal document, e.g. to give them their own
130
+ colours), `.okjt-section-nav` (the sticky bar of sections), `.okjt-site-nav`
131
+ with `.okjt-site-nav-over` / `.okjt-site-nav-solid` (the top bar over a hero
132
+ or on its own background), `.okjt-pill` and `.okjt-pill-<variant>`
133
+ (call-to-action links).
134
+
122
135
  Headings inside the kit's components carry `!` on their font and colour, so a
123
136
  host app's own global `h1`–`h3` styles don't change them.
@@ -9,7 +9,7 @@ function FaqSection({ id = "faq", items, eyebrow = "FAQ", title = "Questions, an
9
9
  /* @__PURE__ */ jsx("div", { className: "lg:col-span-4", children: /* @__PURE__ */ jsx(SectionHeading, { eyebrow, title, text, align: "left", className: "lg:sticky lg:top-28" }) }),
10
10
  /* @__PURE__ */ jsx("div", { className: "space-y-3 lg:col-span-8", children: items.map((item, i) => {
11
11
  const open = openIndex === i;
12
- return /* @__PURE__ */ jsxs("div", { className: `rounded-3xl border transition-colors ${open ? "border-transparent bg-white shadow-[0_20px_50px_-35px_color-mix(in_srgb,var(--color-ink)_50%,transparent)]" : "border-line bg-white/50"}`, children: [
12
+ return /* @__PURE__ */ jsxs("div", { className: `okjt-card rounded-3xl border transition-colors ${open ? "border-transparent bg-surface shadow-[0_20px_50px_-35px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_50%,transparent)]" : "border-line bg-surface/50"}`, children: [
13
13
  /* @__PURE__ */ jsxs(
14
14
  "button",
15
15
  {
@@ -19,7 +19,7 @@ function FaqSection({ id = "faq", items, eyebrow = "FAQ", title = "Questions, an
19
19
  className: "flex w-full items-center justify-between gap-4 px-6 py-5 text-left font-medium text-ink sm:px-8",
20
20
  children: [
21
21
  item.q,
22
- /* @__PURE__ */ jsx("span", { className: `grid h-8 w-8 shrink-0 place-items-center rounded-full transition-all ${open ? "rotate-45 bg-ink text-white" : "bg-tint text-accent"}`, children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4", "aria-hidden": "true" }) })
22
+ /* @__PURE__ */ jsx("span", { className: `grid h-8 w-8 shrink-0 place-items-center rounded-full transition-all ${open ? "rotate-45 bg-fill text-on-ink" : "bg-tint text-accent"}`, children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4", "aria-hidden": "true" }) })
23
23
  ]
24
24
  }
25
25
  ),
@@ -27,14 +27,14 @@ function FeatureExplorer({
27
27
  role: "tab",
28
28
  "aria-selected": selected,
29
29
  onClick: () => setActiveId(group.id),
30
- className: `relative shrink-0 rounded-full px-4 py-2 text-left transition-colors lg:block lg:w-full lg:rounded-none lg:px-6 lg:py-3 ${selected ? "bg-ink text-white lg:bg-transparent lg:text-ink" : "bg-white/60 text-muted hover:text-ink lg:bg-transparent"}`,
30
+ className: `relative shrink-0 rounded-full px-4 py-2 text-left transition-colors lg:block lg:w-full lg:rounded-none lg:px-6 lg:py-3 ${selected ? "bg-fill text-on-ink lg:bg-transparent lg:text-ink" : "bg-surface/60 text-muted hover:text-ink lg:bg-transparent"}`,
31
31
  children: [
32
32
  selected && /* @__PURE__ */ jsx(motion.span, { layoutId: "explorer-bar", className: "absolute -left-px top-0 hidden h-full w-0.5 bg-ink lg:block" }),
33
33
  /* @__PURE__ */ jsx("span", { className: "block whitespace-nowrap text-sm font-semibold lg:text-base lg:font-medium", children: group.eyebrow }),
34
- /* @__PURE__ */ jsxs("span", { className: "hidden text-xs text-faint lg:block", children: [
34
+ group.features?.length > 0 && /* @__PURE__ */ jsxs("span", { className: "hidden text-xs text-faint lg:block", children: [
35
35
  group.features.length,
36
36
  " ",
37
- countLabel
37
+ typeof countLabel === "function" ? countLabel(group.features.length) : countLabel
38
38
  ] })
39
39
  ]
40
40
  },
@@ -52,8 +52,8 @@ function FeatureExplorer({
52
52
  className: "group relative isolate flex min-h-[34rem] flex-col justify-between overflow-hidden rounded-[2rem] p-4 sm:p-6 lg:min-h-[38rem]",
53
53
  children: [
54
54
  /* @__PURE__ */ jsx(Photo, { image: place(`group-${active.id}`), className: "-z-10" }),
55
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 -z-10 bg-gradient-to-t from-ink-deep/85 via-ink-deep/10 to-ink-deep/10" }),
56
- /* @__PURE__ */ jsxs("div", { className: "max-w-sm rounded-3xl border border-white/50 bg-white/75 p-6 shadow-xl backdrop-blur-xl", children: [
55
+ /* @__PURE__ */ jsx("div", { className: "okjt-card-shade absolute inset-0 -z-10 bg-gradient-to-t from-ink-deep/85 via-ink-deep/10 to-ink-deep/10" }),
56
+ /* @__PURE__ */ jsxs("div", { className: "okjt-card max-w-sm rounded-3xl border border-surface/50 bg-surface/75 p-6 shadow-xl backdrop-blur-xl", children: [
57
57
  /* @__PURE__ */ jsx("h3", { className: "!font-display text-2xl !font-normal tracking-tight !text-ink", children: active.title }),
58
58
  /* @__PURE__ */ jsx("div", { className: "mt-3 text-sm leading-relaxed text-body", children: active.summary }),
59
59
  /* @__PURE__ */ jsxs(Link, { to: href(active), className: "mt-5 inline-flex items-center gap-1 text-[11px] font-bold uppercase tracking-[0.15em] text-ink hover:text-accent", children: [
@@ -20,7 +20,7 @@ function FeatureGroup({ group, index }) {
20
20
  /* @__PURE__ */ jsx("h2", { className: "mt-4 !font-display text-4xl !font-light leading-[1.05] tracking-tight !text-ink sm:text-5xl", children: group.title }),
21
21
  /* @__PURE__ */ jsx("div", { className: "mt-5 max-w-2xl text-lg leading-relaxed text-soft", children: group.summary })
22
22
  ] }),
23
- /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-3 gap-3 lg:col-span-5", children: group.stats.map(([value, label]) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-line bg-white/60 p-4", children: [
23
+ /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-3 gap-3 lg:col-span-5", children: group.stats.map(([value, label]) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-line bg-surface/60 p-4", children: [
24
24
  /* @__PURE__ */ jsx("dd", { className: "font-display text-xl font-normal tracking-tight text-ink sm:text-2xl", children: value }),
25
25
  /* @__PURE__ */ jsx("dt", { className: "mt-1 text-xs text-muted", children: label })
26
26
  ] }, label)) })
@@ -28,11 +28,11 @@ function FeatureGroup({ group, index }) {
28
28
  /* @__PURE__ */ jsxs("div", { className: `mt-12 grid gap-5 lg:grid-cols-12 ${flip ? "lg:[&>*:first-child]:order-2" : ""}`, children: [
29
29
  /* @__PURE__ */ jsx(ImageCard, { image: place(`group-${group.id}-card`), tags: [group.eyebrow], title: group.features[0].title, text: group.features[0].text, className: "min-h-[24rem] lg:col-span-5" }),
30
30
  /* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden rounded-[1.75rem] bg-line p-4 sm:p-8 lg:col-span-7", children: [
31
- /* @__PURE__ */ jsx("div", { className: "absolute -right-24 -top-24 h-64 w-64 rounded-full bg-white/50 blur-3xl", "aria-hidden": "true" }),
31
+ /* @__PURE__ */ jsx("div", { className: "absolute -right-24 -top-24 h-64 w-64 rounded-full bg-surface/50 blur-3xl", "aria-hidden": "true" }),
32
32
  /* @__PURE__ */ jsx(MediaFrame, { media, className: "relative" })
33
33
  ] })
34
34
  ] }),
35
- /* @__PURE__ */ jsx("div", { className: "mt-5 grid gap-5 sm:grid-cols-2 lg:grid-cols-3", children: group.features.map((feature) => /* @__PURE__ */ jsxs("article", { className: "flex flex-col rounded-[1.75rem] border border-line bg-white p-6 sm:p-7", children: [
35
+ /* @__PURE__ */ jsx("div", { className: "mt-5 grid gap-5 sm:grid-cols-2 lg:grid-cols-3", children: group.features.map((feature) => /* @__PURE__ */ jsxs("article", { className: "flex flex-col rounded-[1.75rem] border border-line bg-surface p-6 sm:p-7", children: [
36
36
  /* @__PURE__ */ jsx("h3", { className: "!font-display text-xl !font-medium !text-ink", children: feature.title }),
37
37
  /* @__PURE__ */ jsx("div", { className: "mt-3 text-sm leading-relaxed text-soft", children: feature.text }),
38
38
  feature.details.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-5 space-y-2 border-t border-tint pt-5 text-sm text-body", children: feature.details.map((detail) => /* @__PURE__ */ jsxs("li", { className: "flex gap-2.5", children: [
package/dist/ImageCard.js CHANGED
@@ -19,11 +19,11 @@ function ImageCard({
19
19
  Wrapper,
20
20
  {
21
21
  to,
22
- className: `group relative isolate flex flex-col justify-end overflow-hidden rounded-[1.75rem] p-6 text-white shadow-[0_30px_60px_-35px_color-mix(in_srgb,var(--color-ink)_70%,transparent)] sm:p-8 ${className}`,
22
+ className: `group relative isolate flex flex-col justify-end overflow-hidden rounded-[1.75rem] p-6 text-white shadow-[0_30px_60px_-35px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_70%,transparent)] sm:p-8 ${className}`,
23
23
  children: [
24
24
  /* @__PURE__ */ jsx(Photo, { image, position, className: "-z-10" }),
25
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 -z-10 bg-gradient-to-t from-ink-deep/85 via-ink-deep/25 to-transparent" }),
26
- to && /* @__PURE__ */ jsx("span", { className: "absolute right-5 top-5 grid h-10 w-10 place-items-center rounded-full bg-white/15 backdrop-blur transition-colors group-hover:bg-white group-hover:text-ink", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ArrowUpRight, { className: "h-4 w-4" }) }),
25
+ /* @__PURE__ */ jsx("div", { className: "okjt-card-shade absolute inset-0 -z-10 bg-gradient-to-t from-ink-deep/85 via-ink-deep/25 to-transparent" }),
26
+ to && /* @__PURE__ */ jsx("span", { className: "absolute right-5 top-5 grid h-10 w-10 place-items-center rounded-full bg-white/15 backdrop-blur transition-colors group-hover:bg-surface group-hover:text-ink", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ArrowUpRight, { className: "h-4 w-4" }) }),
27
27
  tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-3 flex flex-wrap gap-2", children: tags.map((tag) => /* @__PURE__ */ jsx(Chip, { children: tag }, tag)) }),
28
28
  title && /* @__PURE__ */ jsx("h3", { className: `!font-display !font-normal leading-tight tracking-tight !text-white ${titleClass}`, children: title }),
29
29
  text && /* @__PURE__ */ jsx("div", { className: "mt-2 max-w-md text-sm leading-relaxed text-white/80", children: text }),
package/dist/Journey.js CHANGED
@@ -5,7 +5,7 @@ import { Eyebrow } from "./ui.js";
5
5
  import { SECTION_OFFSET } from "./SectionNav.js";
6
6
  import { useMedia } from "./SiteProvider.js";
7
7
  function JourneyGlance({ journey }) {
8
- return /* @__PURE__ */ jsx("div", { className: "rounded-[2rem] bg-white p-6 shadow-[0_40px_80px_-40px_color-mix(in_srgb,var(--color-ink)_50%,transparent)] sm:p-10", children: /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-2 gap-6 lg:grid-cols-4", children: journey.glance.map(([value, label]) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl bg-tint p-5", children: [
8
+ return /* @__PURE__ */ jsx("div", { className: "rounded-[2rem] bg-surface p-6 shadow-[0_40px_80px_-40px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_50%,transparent)] sm:p-10", children: /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-2 gap-6 lg:grid-cols-4", children: journey.glance.map(([value, label]) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl bg-tint p-5", children: [
9
9
  /* @__PURE__ */ jsx("dd", { className: "font-display text-3xl font-light tracking-tight text-ink sm:text-4xl", children: value }),
10
10
  /* @__PURE__ */ jsx("dt", { className: "mt-1 text-sm text-soft", children: label })
11
11
  ] }, label)) }) });
@@ -17,11 +17,11 @@ function JourneyChapter({ chapter, index, detailsLabel = "The nitty-gritty", tip
17
17
  /* @__PURE__ */ jsxs("div", { className: `${phone ? "lg:col-span-7" : "lg:col-span-5"}`, children: [
18
18
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
19
19
  /* @__PURE__ */ jsx("span", { className: "font-display text-4xl font-extralight text-accent-soft", children: String(index + 1).padStart(2, "0") }),
20
- /* @__PURE__ */ jsx("span", { className: "rounded-full bg-ink px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.15em] text-white", children: chapter.when })
20
+ /* @__PURE__ */ jsx("span", { className: "rounded-full bg-fill px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.15em] text-on-ink", children: chapter.when })
21
21
  ] }),
22
22
  /* @__PURE__ */ jsx("h2", { className: "mt-3 !font-display text-3xl !font-light tracking-tight !text-ink sm:text-4xl", children: chapter.title }),
23
23
  /* @__PURE__ */ jsx("div", { className: "mt-3 leading-relaxed text-soft", children: chapter.intro }),
24
- /* @__PURE__ */ jsx("ol", { className: "mt-6 divide-y divide-tint rounded-3xl border border-line bg-white", children: chapter.steps.map((step, i) => /* @__PURE__ */ jsxs("li", { className: "flex gap-4 p-5", children: [
24
+ /* @__PURE__ */ jsx("ol", { className: "mt-6 divide-y divide-tint rounded-3xl border border-line bg-surface", children: chapter.steps.map((step, i) => /* @__PURE__ */ jsxs("li", { className: "flex gap-4 p-5", children: [
25
25
  /* @__PURE__ */ jsx("span", { className: "grid h-7 w-7 shrink-0 place-items-center rounded-full bg-tint text-xs font-semibold text-accent", children: i + 1 }),
26
26
  /* @__PURE__ */ jsxs("div", { children: [
27
27
  /* @__PURE__ */ jsx("h3", { className: "!font-sans text-base !font-semibold !text-ink", children: step.title }),
@@ -35,11 +35,11 @@ function JourneyChapter({ chapter, index, detailsLabel = "The nitty-gritty", tip
35
35
  detail
36
36
  ] }, detail)) })
37
37
  ] }),
38
- chapter.tip && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex gap-4 rounded-3xl bg-ink p-5 text-white", children: [
38
+ chapter.tip && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex gap-4 rounded-3xl bg-fill p-5 text-on-ink", children: [
39
39
  /* @__PURE__ */ jsx(Lightbulb, { className: "h-5 w-5 shrink-0 text-accent-soft", "aria-hidden": "true" }),
40
40
  /* @__PURE__ */ jsxs("div", { children: [
41
41
  /* @__PURE__ */ jsx("div", { className: "text-[11px] font-semibold uppercase tracking-[0.2em] text-accent-soft", children: tipLabel }),
42
- /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm leading-relaxed text-white/85", children: chapter.tip })
42
+ /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm leading-relaxed text-on-ink/85", children: chapter.tip })
43
43
  ] })
44
44
  ] })
45
45
  ] })
package/dist/LegalPage.js CHANGED
@@ -16,7 +16,7 @@ function Sidebar({ sections, active }) {
16
16
  NavLink,
17
17
  {
18
18
  to: doc.to,
19
- className: ({ isActive }) => `flex min-w-[10rem] flex-1 items-center gap-3 rounded-2xl px-4 py-3 text-sm font-medium transition-colors ${isActive ? "bg-ink text-white" : "bg-white text-body hover:bg-tint"}`,
19
+ className: ({ isActive }) => `flex min-w-[10rem] flex-1 items-center gap-3 rounded-2xl px-4 py-3 text-sm font-medium transition-colors ${isActive ? "bg-fill text-on-ink" : "bg-surface text-body hover:bg-tint"}`,
20
20
  children: [
21
21
  /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
22
22
  doc.label
@@ -66,7 +66,7 @@ function LegalPage({ title, intro, sections }) {
66
66
  /* @__PURE__ */ jsx(SectionNav, { label: "Contents", numbered: true, className: "lg:hidden", sections: sections.map((s) => ({ id: s.id, label: s.title })) }),
67
67
  /* @__PURE__ */ jsx(Container, { className: "pb-16 pt-8 lg:pt-0", children: /* @__PURE__ */ jsxs("div", { className: "mt-4 grid gap-10 lg:mt-12 lg:grid-cols-12", children: [
68
68
  /* @__PURE__ */ jsx("aside", { className: "lg:col-span-4 xl:col-span-3", children: /* @__PURE__ */ jsx(Sidebar, { sections, active }) }),
69
- /* @__PURE__ */ jsxs("article", { className: "rounded-[2rem] bg-white p-6 sm:p-10 lg:col-span-8 xl:col-span-9 xl:p-14", children: [
69
+ /* @__PURE__ */ jsxs("article", { className: "okjt-card rounded-[2rem] bg-surface p-6 sm:p-10 lg:col-span-8 xl:col-span-9 xl:p-14", children: [
70
70
  /* @__PURE__ */ jsx("div", { className: "text-lg leading-relaxed text-body", children: intro }),
71
71
  sections.map((s, i) => /* @__PURE__ */ jsxs("section", { id: s.id, className: `${SECTION_OFFSET} lg:scroll-mt-28 border-t border-tint pt-10 mt-10 first-of-type:mt-10`, children: [
72
72
  /* @__PURE__ */ jsxs("h2", { className: "!font-display text-2xl !font-normal tracking-tight !text-ink", children: [
@@ -34,17 +34,17 @@ function MediaFrame({ media, className = "", variant }) {
34
34
  if (!item) return null;
35
35
  const kind = variant || (item.phone ? "phone" : "browser");
36
36
  if (kind === "phone") {
37
- return /* @__PURE__ */ jsxs("div", { className: `relative mx-auto aspect-[9/19] w-full max-w-[17rem] overflow-hidden rounded-[2.4rem] border-[7px] border-ink bg-ink shadow-[0_40px_80px_-30px_color-mix(in_srgb,var(--color-ink)_70%,transparent)] ${className}`, children: [
38
- /* @__PURE__ */ jsx("div", { className: "absolute left-1/2 top-2 z-10 h-5 w-20 -translate-x-1/2 rounded-full bg-ink", "aria-hidden": "true" }),
39
- /* @__PURE__ */ jsx("div", { className: "h-full overflow-hidden rounded-[1.9rem] bg-white", children: /* @__PURE__ */ jsx(MediaFill, { media: item }) })
37
+ return /* @__PURE__ */ jsxs("div", { className: `relative mx-auto aspect-[9/19] w-full max-w-[17rem] overflow-hidden rounded-[2.4rem] border-[7px] border-fill bg-fill shadow-[0_40px_80px_-30px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_70%,transparent)] ${className}`, children: [
38
+ /* @__PURE__ */ jsx("div", { className: "absolute left-1/2 top-2 z-10 h-5 w-20 -translate-x-1/2 rounded-full bg-fill", "aria-hidden": "true" }),
39
+ /* @__PURE__ */ jsx("div", { className: "h-full overflow-hidden rounded-[1.9rem] bg-surface", children: /* @__PURE__ */ jsx(MediaFill, { media: item }) })
40
40
  ] });
41
41
  }
42
- return /* @__PURE__ */ jsxs("div", { className: `overflow-hidden rounded-2xl border border-white/60 bg-white shadow-[0_40px_80px_-35px_color-mix(in_srgb,var(--color-ink)_55%,transparent)] ${className}`, children: [
42
+ return /* @__PURE__ */ jsxs("div", { className: `overflow-hidden rounded-2xl border border-surface/60 bg-surface shadow-[0_40px_80px_-35px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_55%,transparent)] ${className}`, children: [
43
43
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-line bg-paper px-4 py-2.5", "aria-hidden": "true", children: [
44
44
  /* @__PURE__ */ jsx("span", { className: "h-2.5 w-2.5 rounded-full bg-[#E8C4B8]" }),
45
45
  /* @__PURE__ */ jsx("span", { className: "h-2.5 w-2.5 rounded-full bg-line" }),
46
46
  /* @__PURE__ */ jsx("span", { className: "h-2.5 w-2.5 rounded-full bg-[#C5D4B9]" }),
47
- /* @__PURE__ */ jsx("span", { className: "ml-3 truncate rounded-full bg-white px-3 py-0.5 text-[11px] text-muted", children: item.url })
47
+ /* @__PURE__ */ jsx("span", { className: "ml-3 truncate rounded-full bg-surface px-3 py-0.5 text-[11px] text-muted", children: item.url })
48
48
  ] }),
49
49
  /* @__PURE__ */ jsx("div", { className: "aspect-[16/10] bg-paper", children: /* @__PURE__ */ jsx(MediaFill, { media: item }) })
50
50
  ] });
package/dist/Photo.js CHANGED
@@ -24,7 +24,7 @@ function Photo({ image, phoneImage, width = 1600, alt, position = "center", clas
24
24
  const id = setTimeout(() => setIndex((i) => i + 1), ROTATE_EVERY);
25
25
  return () => clearTimeout(id);
26
26
  }, [rotating, nextSrc, index]);
27
- return /* @__PURE__ */ jsx("div", { className: `absolute inset-0 overflow-hidden bg-gradient-to-br from-accent-soft via-accent to-body ${className}`, children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: !failed && /* @__PURE__ */ jsxs(
27
+ return /* @__PURE__ */ jsx("div", { className: `okjt-photo absolute inset-0 overflow-hidden bg-gradient-to-br from-accent-soft via-accent to-body ${className}`, children: /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: !failed && /* @__PURE__ */ jsxs(
28
28
  motion.picture,
29
29
  {
30
30
  initial: { opacity: 0 },
@@ -15,14 +15,14 @@ function PricingSection({ id = "pricing", eyebrow = "Pricing", title, text, plan
15
15
  /* @__PURE__ */ jsx("div", { className: "mx-auto mt-14 grid max-w-5xl gap-6 md:grid-cols-2", children: plans.map((plan) => /* @__PURE__ */ jsxs(
16
16
  "div",
17
17
  {
18
- className: `relative flex flex-col overflow-hidden rounded-[2rem] p-8 sm:p-10 ${plan.highlight ? "bg-ink text-white shadow-[0_40px_80px_-40px_color-mix(in_srgb,var(--color-ink)_80%,transparent)]" : "border border-line bg-white"}`,
18
+ className: `relative flex flex-col overflow-hidden rounded-[2rem] p-8 sm:p-10 ${plan.highlight ? "bg-fill text-on-ink shadow-[0_40px_80px_-40px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_80%,transparent)]" : "border border-line bg-surface"}`,
19
19
  children: [
20
20
  plan.highlight && /* @__PURE__ */ jsx("div", { className: "absolute -right-16 -top-16 h-48 w-48 rounded-full bg-accent-soft/20 blur-2xl", "aria-hidden": "true" }),
21
21
  /* @__PURE__ */ jsx("div", { className: `text-xs font-semibold uppercase tracking-[0.2em] ${plan.highlight ? "text-accent-soft" : "text-accent"}`, children: plan.name }),
22
- /* @__PURE__ */ jsx("div", { className: `mt-3 font-display text-3xl font-light tracking-tight sm:text-4xl ${plan.highlight ? "text-white" : "text-ink"}`, children: plan.price }),
23
- /* @__PURE__ */ jsx("div", { className: `mt-2 text-sm ${plan.highlight ? "text-white/70" : "text-soft"}`, children: plan.tagline }),
22
+ /* @__PURE__ */ jsx("div", { className: `mt-3 font-display text-3xl font-light tracking-tight sm:text-4xl ${plan.highlight ? "text-on-ink" : "text-ink"}`, children: plan.price }),
23
+ /* @__PURE__ */ jsx("div", { className: `mt-2 text-sm ${plan.highlight ? "text-on-ink/70" : "text-soft"}`, children: plan.tagline }),
24
24
  /* @__PURE__ */ jsx("ul", { className: "mt-8 flex-1 space-y-3 text-sm", children: plan.lines.map((feature) => /* @__PURE__ */ jsxs("li", { className: "flex gap-3", children: [
25
- /* @__PURE__ */ jsx("span", { className: `mt-0.5 grid h-5 w-5 shrink-0 place-items-center rounded-full ${plan.highlight ? "bg-white/10 text-accent-soft" : "bg-tint text-accent"}`, children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) }),
25
+ /* @__PURE__ */ jsx("span", { className: `mt-0.5 grid h-5 w-5 shrink-0 place-items-center rounded-full ${plan.highlight ? "bg-on-ink/10 text-accent-soft" : "bg-tint text-accent"}`, children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) }),
26
26
  feature
27
27
  ] }, feature)) }),
28
28
  /* @__PURE__ */ jsx(PillLink, { to: plan.cta.to, variant: plan.highlight ? "light" : "dark", className: "mt-10", children: plan.cta.label })
@@ -13,14 +13,14 @@ function SectionNav({ sections, label, numbered = false, className = "" }) {
13
13
  const left = chip.offsetLeft - nav.clientWidth / 2 + chip.clientWidth / 2;
14
14
  nav.scrollTo?.({ left, behavior: "smooth" });
15
15
  }, [active]);
16
- return /* @__PURE__ */ jsx("div", { className: `sticky top-[4.25rem] z-30 border-y border-line/70 bg-tint/90 backdrop-blur-xl ${className}`, children: /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("nav", { ref: bar, "aria-label": label, className: "-mx-4 flex gap-2 overflow-x-auto px-4 py-3 [scrollbar-width:none] [mask-image:linear-gradient(to_right,black_calc(100%-2.5rem),transparent)]", children: sections.map((section, i) => {
16
+ return /* @__PURE__ */ jsx("div", { className: `okjt-section-nav sticky top-[var(--okjt-nav-h,4.25rem)] z-30 border-y border-line/70 bg-tint/90 backdrop-blur-xl ${className}`, children: /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("nav", { ref: bar, "aria-label": label, className: "-mx-4 flex items-center gap-2 overflow-x-auto px-4 py-3 [scrollbar-width:none] [mask-image:linear-gradient(to_right,black_calc(100%-2.5rem),transparent)]", children: sections.map((section, i) => {
17
17
  const current = active === section.id;
18
18
  return /* @__PURE__ */ jsxs(
19
19
  "a",
20
20
  {
21
21
  href: `#${section.id}`,
22
22
  "aria-current": current ? "location" : void 0,
23
- className: `shrink-0 rounded-full px-4 py-2 text-xs font-semibold transition-colors ${current ? "bg-ink text-white" : "bg-white text-soft hover:text-ink"}`,
23
+ className: `shrink-0 rounded-full px-4 py-2 text-xs font-semibold transition-colors ${current ? "bg-fill text-on-ink" : "bg-surface text-soft hover:text-ink"}`,
24
24
  children: [
25
25
  numbered && /* @__PURE__ */ jsx("span", { className: `mr-1.5 tabular-nums ${current ? "text-accent-soft" : "text-faint"}`, children: String(i + 1).padStart(2, "0") }),
26
26
  section.label
@@ -16,8 +16,8 @@ function ShowcaseCarousel({ eyebrow, title, text, items }) {
16
16
  /* @__PURE__ */ jsxs("div", { children: [
17
17
  /* @__PURE__ */ jsx(SectionHeading, { eyebrow, title, text, align: "left" }),
18
18
  /* @__PURE__ */ jsxs("div", { className: "mt-8 flex items-center gap-3", children: [
19
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => go(-1), "aria-label": "Previous", className: "grid h-12 w-12 place-items-center rounded-full bg-white text-ink shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--color-ink)_35%,transparent)] transition-transform hover:-translate-x-0.5", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5" }) }),
20
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => go(1), "aria-label": "Next", className: "grid h-12 w-12 place-items-center rounded-full bg-white text-ink shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--color-ink)_35%,transparent)] transition-transform hover:translate-x-0.5", children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5" }) }),
19
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => go(-1), "aria-label": "Previous", className: "grid h-12 w-12 place-items-center rounded-full bg-surface text-ink shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_35%,transparent)] transition-transform hover:-translate-x-0.5", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5" }) }),
20
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => go(1), "aria-label": "Next", className: "grid h-12 w-12 place-items-center rounded-full bg-surface text-ink shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_35%,transparent)] transition-transform hover:translate-x-0.5", children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5" }) }),
21
21
  /* @__PURE__ */ jsxs("span", { className: "ml-3 text-sm tabular-nums text-muted", "aria-live": "polite", children: [
22
22
  index + 1,
23
23
  " / ",
@@ -39,7 +39,7 @@ function ShowcaseCarousel({ eyebrow, title, text, items }) {
39
39
  animate: { opacity: 1, x: 0 },
40
40
  exit: { opacity: 0, x: -40 },
41
41
  transition: { duration: 0.4 },
42
- className: `relative overflow-hidden rounded-[2rem] border-[6px] border-white bg-white shadow-[0_40px_80px_-30px_color-mix(in_srgb,var(--color-ink)_60%,transparent)] ${shape}`,
42
+ className: `relative overflow-hidden rounded-[2rem] border-[6px] border-surface bg-surface shadow-[0_40px_80px_-30px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_60%,transparent)] ${shape}`,
43
43
  children: [
44
44
  /* @__PURE__ */ jsx(MediaFill, { media: item.media }),
45
45
  /* @__PURE__ */ jsxs("div", { className: "absolute inset-x-0 bottom-0 bg-gradient-to-t from-ink-deep/90 via-ink-deep/60 to-transparent p-4 pt-12 text-white sm:p-6 sm:pt-24", children: [
@@ -25,7 +25,7 @@ function SiteFooter({ cta = true }) {
25
25
  const shown = (link) => link.signedIn === void 0 || link.signedIn === Boolean(isAuthenticated);
26
26
  return /* @__PURE__ */ jsxs("footer", { className: "pt-10", children: [
27
27
  cta && footer.cta && /* @__PURE__ */ jsx(FooterCta, { cta: footer.cta }),
28
- /* @__PURE__ */ jsx("div", { className: "px-2 pb-2 sm:px-4 sm:pb-4", children: /* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden rounded-[2rem] bg-ink text-white", children: [
28
+ /* @__PURE__ */ jsx("div", { className: "px-2 pb-2 sm:px-4 sm:pb-4", children: /* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden rounded-[2rem] bg-panel text-white", children: [
29
29
  /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute -bottom-10 right-0 select-none font-display text-[9rem] font-semibold leading-none tracking-tighter text-white/[0.04] sm:text-[16rem] lg:text-[22rem]", "aria-hidden": "true", children: footer.watermark }),
30
30
  /* @__PURE__ */ jsxs(Container, { className: "relative py-14 lg:py-20", children: [
31
31
  /* @__PURE__ */ jsxs("div", { className: "grid gap-12 lg:grid-cols-12", children: [
@@ -24,7 +24,7 @@ function useScrollToHash() {
24
24
  }
25
25
  function SiteLayout({ overlay = false, cta = true, children }) {
26
26
  useScrollToHash();
27
- return /* @__PURE__ */ jsxs("div", { className: "min-h-dvh bg-tint font-sans text-ink antialiased", children: [
27
+ return /* @__PURE__ */ jsxs("div", { className: "okjt-site min-h-dvh bg-tint font-sans text-ink antialiased", children: [
28
28
  /* @__PURE__ */ jsx(Seo, {}),
29
29
  /* @__PURE__ */ jsx(SiteNav, { overlay }),
30
30
  /* @__PURE__ */ jsx("main", { className: overlay ? "" : "pt-24", children }),
package/dist/SiteNav.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  import { Link, NavLink } from "react-router-dom";
4
4
  import { ChevronDown, Menu, X } from "lucide-react";
5
5
  import { useSignedIn, useSite } from "./SiteProvider.js";
@@ -11,6 +11,20 @@ function SiteNav({ overlay = false }) {
11
11
  const [open, setOpen] = useState(false);
12
12
  const [scrolled, setScrolled] = useState(false);
13
13
  const [mega, setMega] = useState(false);
14
+ const header = useRef(null);
15
+ useEffect(() => {
16
+ const el = header.current;
17
+ if (!el || typeof ResizeObserver === "undefined") return void 0;
18
+ const root = document.documentElement;
19
+ const set = () => root.style.setProperty("--okjt-nav-h", `${el.offsetHeight}px`);
20
+ set();
21
+ const observer = new ResizeObserver(set);
22
+ observer.observe(el, { box: "border-box" });
23
+ return () => {
24
+ observer.disconnect();
25
+ root.style.removeProperty("--okjt-nav-h");
26
+ };
27
+ }, []);
14
28
  useEffect(() => {
15
29
  const onScroll = () => setScrolled(window.scrollY > 24);
16
30
  onScroll();
@@ -30,9 +44,9 @@ function SiteNav({ overlay = false }) {
30
44
  setMega(false);
31
45
  setOpen(false);
32
46
  };
33
- const pillLink = ({ isActive }) => `rounded-full px-4 py-2 text-[11px] font-semibold uppercase tracking-[0.12em] transition-colors ${isActive ? "bg-white text-ink shadow-sm" : light ? "text-white/85 hover:text-white" : "text-soft hover:text-ink"}`;
47
+ const pillLink = ({ isActive }) => `rounded-full px-4 py-2 text-[11px] font-semibold uppercase tracking-[0.12em] transition-colors ${isActive ? "bg-surface text-ink shadow-sm" : light ? "text-white/85 hover:text-white" : "text-soft hover:text-ink"}`;
34
48
  const isPage = (to) => !to.includes("#");
35
- return /* @__PURE__ */ jsxs("header", { onMouseLeave: () => setMega(false), className: `fixed inset-x-0 top-0 z-40 transition-all duration-300 ${light ? "py-5" : "border-b border-line/70 bg-tint/85 py-3 backdrop-blur-xl"}`, children: [
49
+ return /* @__PURE__ */ jsxs("header", { ref: header, onMouseLeave: () => setMega(false), className: `okjt-site-nav ${light ? "okjt-site-nav-over" : "okjt-site-nav-solid"} fixed inset-x-0 top-0 z-40 transition-all duration-300 ${light ? "py-5" : "border-b border-line/70 bg-tint/85 py-3 backdrop-blur-xl"}`, children: [
36
50
  /* @__PURE__ */ jsxs(Container, { className: "flex items-center justify-between gap-4", children: [
37
51
  /* @__PURE__ */ jsx(Logo, { light }),
38
52
  /* @__PURE__ */ jsx("nav", { "aria-label": "Main", className: `hidden items-center gap-1 rounded-full p-1 lg:flex ${light ? "border border-white/30 bg-white/10 backdrop-blur-md" : "border border-line bg-tint/70"}`, children: nav.map((item) => {
@@ -72,7 +86,7 @@ function SiteNav({ overlay = false }) {
72
86
  )
73
87
  ] }),
74
88
  mega && megaItem && /* @__PURE__ */ jsx(megaItem.mega.Menu, { id: megaItem.mega.id, onNavigate: closeAll }),
75
- open && /* @__PURE__ */ jsx(Container, { className: "lg:hidden", children: /* @__PURE__ */ jsxs("nav", { "aria-label": "Main", className: "mt-3 max-h-[calc(100svh-6rem)] overflow-y-auto rounded-3xl border border-line bg-white p-3 shadow-xl", children: [
89
+ open && /* @__PURE__ */ jsx(Container, { className: "lg:hidden", children: /* @__PURE__ */ jsxs("nav", { "aria-label": "Main", className: "mt-3 max-h-[calc(100svh-6rem)] overflow-y-auto rounded-3xl border border-line bg-surface p-3 shadow-xl", children: [
76
90
  nav.map((item) => item.mega ? /* @__PURE__ */ jsx(item.mega.MobileList, { onNavigate: closeAll }, item.to) : /* @__PURE__ */ jsx(Link, { to: item.to, onClick: () => setOpen(false), className: "block rounded-2xl px-4 py-3 text-body hover:bg-tint", children: item.label }, item.to)),
77
91
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-3 border-t border-line pt-3", children: [
78
92
  /* @__PURE__ */ jsx(PillLink, { to: isAuthenticated ? links.home.to : links.signIn.to, variant: "outline", size: "sm", className: "flex-1", children: isAuthenticated ? links.home.label : links.signIn.label }),
package/dist/ui.js CHANGED
@@ -10,8 +10,8 @@ function Logo({ light = false, className = "" }) {
10
10
  return /* @__PURE__ */ jsx(Link, { to: "/", className: `flex items-center gap-2.5 ${className}`, "aria-label": `${brand.name} home`, children: /* @__PURE__ */ jsx("img", { src: light ? brand.logo.light : brand.logo.dark, alt: "", className: "h-8 w-auto" }) });
11
11
  }
12
12
  const PILL_VARIANTS = {
13
- dark: "bg-ink text-white hover:bg-body shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--color-ink)_60%,transparent)]",
14
- light: "bg-white text-ink hover:bg-tint shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--color-ink)_35%,transparent)]",
13
+ dark: "bg-fill text-on-ink hover:bg-fill-hover shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_60%,transparent)]",
14
+ light: "bg-surface text-ink hover:bg-tint shadow-[0_10px_30px_-12px_color-mix(in_srgb,var(--okjt-shadow,var(--color-ink))_35%,transparent)]",
15
15
  outline: "border border-line-strong text-body hover:border-accent hover:text-ink",
16
16
  glass: "border border-white/40 bg-white/10 text-white backdrop-blur hover:bg-white/20"
17
17
  };
@@ -21,7 +21,7 @@ function PillLink({ to, variant = "dark", size = "md", arrow = false, className
21
21
  Link,
22
22
  {
23
23
  to,
24
- className: `inline-flex items-center justify-center gap-2 rounded-full font-semibold uppercase tracking-[0.08em] transition-colors ${sizes[size]} ${PILL_VARIANTS[variant]} ${className}`,
24
+ className: `okjt-pill okjt-pill-${variant} inline-flex items-center justify-center gap-2 rounded-full font-semibold uppercase tracking-[0.08em] transition-colors ${sizes[size]} ${PILL_VARIANTS[variant]} ${className}`,
25
25
  ...rest,
26
26
  children: [
27
27
  children,
@@ -34,7 +34,7 @@ function Eyebrow({ light = false, className = "", children }) {
34
34
  return /* @__PURE__ */ jsx("div", { className: `text-[11px] font-semibold uppercase tracking-[0.22em] ${light ? "text-white/75" : "text-accent"} ${className}`, children });
35
35
  }
36
36
  function Chip({ light = true, children }) {
37
- return /* @__PURE__ */ jsx("span", { className: `inline-flex rounded-full px-3 py-1 text-[11px] font-semibold ${light ? "bg-white text-ink" : "bg-ink/5 text-body"}`, children });
37
+ return /* @__PURE__ */ jsx("span", { className: `inline-flex rounded-full px-3 py-1 text-[11px] font-semibold ${light ? "bg-surface text-ink" : "bg-ink/5 text-body"}`, children });
38
38
  }
39
39
  function SectionHeading({ eyebrow, title, text, align = "center", light = false, as = "h2", className = "" }) {
40
40
  const Tag = as;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okjt/site",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Public pages for OKJTech projects: layout, navigation, footer, hero, feature, pricing, FAQ and legal sections",
5
5
  "type": "module",
6
6
  "license": "MIT",