diff --git a/src/shared/ui/TechStack/index.ts b/src/shared/ui/TechStack/index.ts
new file mode 100644
index 0000000..7b8d6da
--- /dev/null
+++ b/src/shared/ui/TechStack/index.ts
@@ -0,0 +1 @@
+export { TechStackBrick, TechStackGrid } from './ui/TechStack'
diff --git a/src/shared/ui/TechStack/ui/TechStack.test.tsx b/src/shared/ui/TechStack/ui/TechStack.test.tsx
new file mode 100644
index 0000000..21cd240
--- /dev/null
+++ b/src/shared/ui/TechStack/ui/TechStack.test.tsx
@@ -0,0 +1,62 @@
+import { describe, it, expect } from 'vitest'
+import { render, screen } from '@testing-library/react'
+import { TechStackBrick, TechStackGrid } from './TechStack'
+
+describe('TechStackBrick', () => {
+ describe('rendering', () => {
+ it('renders the technology name', () => {
+ render()
+ expect(screen.getByText('TypeScript')).toBeInTheDocument()
+ })
+ })
+
+ describe('styling', () => {
+ it('has brutal-border class', () => {
+ const { container } = render()
+ expect(container.firstChild).toHaveClass('brutal-border')
+ })
+ it('has brutal-shadow class', () => {
+ const { container } = render()
+ expect(container.firstChild).toHaveClass('brutal-shadow')
+ })
+ it('name span has uppercase and tracking-wide', () => {
+ render()
+ const span = screen.getByText('Go')
+ expect(span).toHaveClass('uppercase', 'tracking-wide')
+ })
+ it('applies custom className', () => {
+ const { container } = render()
+ expect(container.firstChild).toHaveClass('w-full')
+ })
+ })
+})
+
+describe('TechStackGrid', () => {
+ describe('rendering', () => {
+ it('renders all skill names', () => {
+ render()
+ expect(screen.getByText('React')).toBeInTheDocument()
+ expect(screen.getByText('TypeScript')).toBeInTheDocument()
+ expect(screen.getByText('Go')).toBeInTheDocument()
+ })
+ it('renders correct number of bricks', () => {
+ const { container } = render()
+ expect(container.firstChild!.childNodes).toHaveLength(3)
+ })
+ it('renders empty grid with no skills', () => {
+ const { container } = render()
+ expect(container.firstChild!.childNodes).toHaveLength(0)
+ })
+ })
+
+ describe('layout', () => {
+ it('has grid class', () => {
+ const { container } = render()
+ expect(container.firstChild).toHaveClass('grid')
+ })
+ it('applies custom className', () => {
+ const { container } = render()
+ expect(container.firstChild).toHaveClass('my-custom')
+ })
+ })
+})
diff --git a/src/shared/ui/TechStack/ui/TechStack.tsx b/src/shared/ui/TechStack/ui/TechStack.tsx
new file mode 100644
index 0000000..f7fe5de
--- /dev/null
+++ b/src/shared/ui/TechStack/ui/TechStack.tsx
@@ -0,0 +1,58 @@
+import { cn } from '$shared/lib'
+
+interface TechStackBrickProps {
+ /**
+ * Technology name displayed in the brick
+ */
+ name: string
+ /**
+ * CSS classes
+ */
+ className?: string
+}
+
+/**
+ * Single technology label brick with brutalist border and hover effect.
+ */
+export function TechStackBrick({ name, className }: TechStackBrickProps) {
+ return (
+
+ {name}
+
+ )
+}
+
+interface TechStackGridProps {
+ /**
+ * List of technology names to render as bricks
+ */
+ skills: string[]
+ /**
+ * CSS classes
+ */
+ className?: string
+}
+
+/**
+ * Responsive grid of TechStackBrick items.
+ */
+export function TechStackGrid({ skills, className }: TechStackGridProps) {
+ return (
+
+ {skills.map((skill, index) => (
+
+ ))}
+
+ )
+}