| name | pine-design-review |
| description | Design-token, SCSS, accessibility, and Figma Code Connect review for Pine. Covers component token files (`*.tokens.scss`), `:host` custom-property patterns, `:host-context([data-theme=dark])` dark-mode support, keyboard / ARIA / focus, semantic HTML, and `.figma.ts` alignment. |
Design Review (Pine)
Review Pine component changes for design-token discipline, accessibility,
and Figma alignment. Pine components are leaf-level UI building blocks
shipped to every consuming app — a11y and visual consistency matter
disproportionately.
When to Use
- After any SCSS, token, JSX-markup, or
*.figma.ts change
- As part of the gauntlet whenever component code or styles change
- When new components or variants are added
Pine Design Context
- Component tokens live in
<component>/<pds-name>.tokens.scss,
importing from the shared @kajabi-ui/styles package. Each component
exposes its own scoped CSS custom properties on :host.
- Token naming: semantic-first
(
--pine-color-background-container,
--pine-color-text-strong), with core palette
(--pine-color-green-100) reserved for explicit ramp work like
dark-mode shims.
- Dark mode: Pine uses
:host-context([data-theme=dark]) inside
component token files to remap the same custom properties to dark
palette steps.
- Figma Code Connect (
*.figma.ts): declarative mapping of Figma
component variants to Pine props. Updated whenever a public prop
changes.
- Storybook stories live in
<component>/stories/. New variants
add argTypes entries and at least one exposed example.
- Auto-generated
readme.md is regenerated by Stencil's build;
never hand-edit.
Design Review Checklist
BLOCKER Severity
- Raw hex /
rgb() / rgba() in *.scss when a Pine token
applies (e.g. color: #f8f8f8 where
var(--pine-color-text) or var(--pine-color-grey-100) is right).
Allowed only with an explicit stylelint-disable + reason comment
(e.g. inside an iframe content stylesheet, or for an SVG fill that
can't read variables).
- Wrong Pine token name — see the kp
CLAUDE.md "common
hallucinated tokens" table. Recurring offenders:
--pine-color-gray-* (American spelling) → --pine-color-grey-*
--pine-color-grey-50 → --pine-color-grey-050 (leading zero)
--pine-shadow-md → --pine-box-shadow-100
--pine-spacing-* → --pine-dimension-*
--pine-color-text-primary for body text → --pine-color-text or
--pine-color-text-strong
- Missing component tokens file — Every new component with bespoke
colors / dimensions / shadows needs a
<pds-name>.tokens.scss
exposing the values as custom properties on :host. Inline
hardcoded var(--pine-color-*) in the main *.scss without a
tokens file is BLOCKER.
- Dark-mode regression — Removing or breaking a
:host-context([data-theme=dark]) block, or introducing a new
hardcoded color that doesn't respond to dark mode.
- a11y: interactive element without keyboard access —
Non-
<button> / non-<a> element with a click handler and no
onKeyDown for Enter/Space, no role="button" + tabIndex={0}.
- a11y: icon-only button without
aria-label — Any <button>
rendered as icon-only (e.g. dropdown / close affordances) must carry
an aria-label or visually-hidden text.
- a11y: form input without label —
<input>, <textarea>,
<select> must have an associated label via wrapping or
aria-labelledby.
outline: none without a visible focus replacement — Removing
the default focus outline requires a :focus-visible rule with
outline: var(--pine-outline-focus) or equivalent.
- Hand-edited
readme.md — Auto-generated; rebuild instead.
.figma.ts not updated for a renamed / removed public prop —
Figma Code Connect goes out of sync and design tooling breaks.
SHOULD FIX Severity
- Component values not exposed via
:host custom properties —
Internal-only values are fine inline, but anything a consumer might
reasonably want to override should be a CSS custom property declared
in the tokens file.
- Magic numbers in
*.scss (16px, 8px) where
var(--pine-dimension-*) applies.
- Missing Storybook story arg for new prop / variant — Every
consumer-visible prop should be exposed in
argTypes so reviewers
and consumers can exercise it.
.figma.ts not updated when a public prop is added — Code
Connect mappings get stale; align the new prop now.
- Inconsistent dark-mode treatment across sibling components — New
dark-mode tokens should use the same step convention as siblings
(
color-900 bg, color-800 hover, color-400 dot, color-100
text for the colored sentiments; grey-800 bg, grey-600 hover,
grey-300 dot, grey-100 text for neutral).
:host selector specificity — Avoid escaping the shadow boundary
with ::part / ::slotted unless intentionally exposing styling
hooks to consumers.
- Semantic vs core token choice — Prefer
var(--pine-color-background-container) over
var(--pine-color-white) when the meaning is "the component sits
on a container surface."
- Heading-level skip in JSX — A component that renders headings
should accept a
headingLevel prop rather than hard-coding <h2>.
- Color-only state signal — A state difference conveyed only by
hue (e.g. red border vs grey border). Pair with an icon, label, or
text.
CONSIDER Severity
- Mixin extraction — A new utility could move into a shared mixin
if used in more than one component.
- Token addition vs reuse — New token whose value matches an
existing one; coordinate with the DS team.
- Animation respect for
prefers-reduced-motion — Animated
transitions should honor the user preference media query.
- Touch target < 44×44 px — Compact-variant decisions deserve a
documented rationale.
- Story documentation block — Components benefit from a
prop-description docblock in
stories/<name>.docs.mdx.
Accessibility quick checklist
For each interactive element in the diff:
For modals / overlays / popovers / dropdowns:
Pine token quick reference
| Family | Examples |
|---|
| Core palette | --pine-color-{green,red,blue,yellow,grey,purple,…}-{050,100,…,950} |
| Semantic surfaces | --pine-color-background-container, --pine-color-background-inset |
| Semantic text | --pine-color-text, --pine-color-text-strong, --pine-color-text-muted |
| Semantic borders | --pine-color-border, --pine-color-border-subtle |
| Component-scoped | --pine-chip-color-success, --pine-chip-color-success-text, --pine-chip-color-success-dot (declared on :host in *.tokens.scss) |
| Dimensions | --pine-dimension-{none,2xs,xs,sm,md,lg,xl,2xl} |
| Box shadows | --pine-box-shadow-{050,100,150,200,300,400,500} |
| Border radius | --pine-border-radius-{sm,md,lg,full} |
| Focus outline | --pine-outline-focus, --pine-outline-focus-danger |
Output Format
Number items sequentially across all sections — do not restart
numbering in each section. Section headers still show per-section
counts.
## Pine Design Review
**Files Reviewed:** [list]
**Components Affected:** [pds-<names>]
**Areas:** tokens | scss | a11y | figma | story
**Overall:** APPROVED | NEEDS CHANGES | BLOCKER
### BLOCKERS ([count])
1. [Hardcoded color when token applies, wrong token name, dark-mode regression, a11y violation]
### SHOULD FIX ([count])
2. [Token exposure, magic numbers, missing story arg, stale .figma.ts, color-only signal]
### CONSIDER ([count])
3. [Mixin extraction, token reuse, reduced-motion, touch target]
### What's Good
[Solid token discipline, consistent dark-mode steps, clean a11y]
Anti-Patterns in Reviewing
- Do NOT flag Stylelint-formatted output; Stylelint handles that.
- Do NOT push for full new-token additions inside a component PR;
coordinate with the DS team.
- Do NOT review
dist/ or auto-generated readme.md.
- Do NOT block on
!important if there's a clear cascade-fight
comment.
- Do NOT require animations everywhere; only review them when present.
- Do NOT require a Storybook story for a CSS-only fix that doesn't
change visible variants.