diff --git a/app/components/type/ContentLockup/ContentLockup.view.tsx b/app/components/type/ContentLockup/ContentLockup.view.tsx
index 0707a97..47ad212 100644
--- a/app/components/type/ContentLockup/ContentLockup.view.tsx
+++ b/app/components/type/ContentLockup/ContentLockup.view.tsx
@@ -1,6 +1,7 @@
"use client";
import { memo } from "react";
+import NextLink from "next/link";
import Button from "../../buttons/Button";
import { contentLockupShapePath, getAssetPath } from "../../../../lib/assetUtils";
import type { ContentLockupViewProps } from "./ContentLockup.types";
@@ -98,14 +99,13 @@ function ContentLockupView({
)}
- {/* Link for feature variant */}
{variant === "feature" && linkText && linkHref && (
-
{linkText}
-
+
)}
{/* CTA Button */}
diff --git a/docs/guides/static-assets.md b/docs/guides/static-assets.md
index 22c2c19..46313e1 100644
--- a/docs/guides/static-assets.md
+++ b/docs/guides/static-assets.md
@@ -8,7 +8,7 @@ Convention for files served from `public/`. Path helpers live in
```
public/
assets/
- icons/ # UI chrome (alert, close, help, pointer)
+ icons/ # UI chrome (close, help) + FeatureGrid card glyphs
logos/ # Brand + social lockups
partners/ # Logo wall partner SVGs (kebab org slug)
marketing/ # Hero, feature panels, section numbers, avatars, banners, book cover
@@ -25,7 +25,7 @@ public/
| Location | Used for | Resolution |
| --- | --- | --- |
-| `public/assets/icons/` | Static chrome served by URL (`icon-close.svg`, `icon-help.svg`) | `ASSETS.ICON_*` |
+| `public/assets/icons/` | Static chrome served by URL (`icon-close.svg`, `icon-help.svg`) and FeatureGrid card glyphs (`icon-git-branch.svg`, …) | `ASSETS.ICON_*`, `featureIconPath()` |
| `app/components/asset/icon/` | Bundled create-flow / nav SVGs imported by `Icon.tsx` | Webpack import, not `public/` |
Do not duplicate the same glyph in both places unless migrating between systems.
@@ -61,7 +61,8 @@ stage. Raster → SVG conversion is tracked in
| Path | Used by | Disposition |
| --- | --- | --- |
| `logos/partners/*.svg` (×6) | LogoWall | **Done** — SVG (kebab org slug, no `logo-` prefix) |
-| `marketing/feature-*.svg` (×4) | FeatureGrid | Exported from Figma Section/Feature-Grid (18847:22410) |
+| `marketing/feature-*.svg` (×4) | Mini cards | Panel art (`support`, `exercises`, `guidance`, `tools`) |
+| `icons/icon-{git-branch,arrow-left-right,door-open,message-square-share}.svg` | FeatureGrid | Card glyphs from Figma Section/Feature-Grid (18632:10668) |
| `marketing/section-number-*.svg` (×3) | SectionNumber | **Done** — SVG |
| `marketing/avatar-*.svg` (×3) | Avatar / ASSETS | **Done** — SVG |
| `marketing/hero-image.png` | HeroBanner | **Design review** — likely keep raster |
diff --git a/lib/assetUtils.ts b/lib/assetUtils.ts
index 3661369..1be1024 100644
--- a/lib/assetUtils.ts
+++ b/lib/assetUtils.ts
@@ -114,7 +114,7 @@ export function featurePanelPath(key: FeaturePanelKey): string {
return `assets/marketing/feature-${key}.svg`;
}
-/** Feature-grid card glyphs (Figma **18632:10668**). */
+/** Feature-grid card glyphs in `public/assets/icons/` (Figma **18632:10668**). */
export type FeatureIconKey =
| "git-branch"
| "arrow-left-right"
@@ -122,7 +122,7 @@ export type FeatureIconKey =
| "message-square-share";
export function featureIconPath(key: FeatureIconKey): string {
- return `assets/marketing/feature-icon-${key}.svg`;
+ return `assets/icons/icon-${key}.svg`;
}
/** Case study card artwork in `public/assets/case-study/`. */
diff --git a/public/assets/marketing/feature-icon-arrow-left-right.svg b/public/assets/icons/icon-arrow-left-right.svg
similarity index 100%
rename from public/assets/marketing/feature-icon-arrow-left-right.svg
rename to public/assets/icons/icon-arrow-left-right.svg
diff --git a/public/assets/marketing/feature-icon-door-open.svg b/public/assets/icons/icon-door-open.svg
similarity index 100%
rename from public/assets/marketing/feature-icon-door-open.svg
rename to public/assets/icons/icon-door-open.svg
diff --git a/public/assets/marketing/feature-icon-git-branch.svg b/public/assets/icons/icon-git-branch.svg
similarity index 100%
rename from public/assets/marketing/feature-icon-git-branch.svg
rename to public/assets/icons/icon-git-branch.svg
diff --git a/public/assets/marketing/feature-icon-message-square-share.svg b/public/assets/icons/icon-message-square-share.svg
similarity index 100%
rename from public/assets/marketing/feature-icon-message-square-share.svg
rename to public/assets/icons/icon-message-square-share.svg
diff --git a/tests/components/FeatureGrid.test.tsx b/tests/components/FeatureGrid.test.tsx
index 6400edc..c5570a8 100644
--- a/tests/components/FeatureGrid.test.tsx
+++ b/tests/components/FeatureGrid.test.tsx
@@ -132,6 +132,7 @@ describe("FeatureGrid (behavioral tests)", () => {
expect(icon).toHaveAttribute("width", "40");
expect(icon).toHaveAttribute("height", "40");
expect(icon).toHaveAttribute("alt", "");
+ expect(icon.getAttribute("src")).toMatch(/^\/assets\/icons\/icon-/);
});
});
});
diff --git a/tests/components/type/ContentLockup.test.tsx b/tests/components/type/ContentLockup.test.tsx
index d5f0b7b..d99ecb9 100644
--- a/tests/components/type/ContentLockup.test.tsx
+++ b/tests/components/type/ContentLockup.test.tsx
@@ -63,4 +63,24 @@ describe("ContentLockup", () => {
expect(description.className).toContain("text-small-paragraph");
expect(description.className).toContain("sm:text-large-paragraph");
});
+
+ it("renders the feature lockup CTA as an inline text link", () => {
+ renderWithProviders(
+ ,
+ );
+
+ const link = screen.getByRole("link", { name: "Explore the toolkit" });
+ expect(link).toHaveAttribute("href", "/learn");
+ expect(link.className).toMatch(/underline/);
+ expect(link.className).toMatch(/w-fit/);
+ expect(link.className).not.toMatch(/px-1/);
+ expect(link.className).not.toMatch(/focus:ring-2/);
+ expect(link.className).toMatch(/focus-visible:outline/);
+ });
});