diff --git a/packages/lib/components/card/Overview.mdx b/packages/lib/components/card/Overview.mdx
new file mode 100644
index 0000000..7b10c51
--- /dev/null
+++ b/packages/lib/components/card/Overview.mdx
@@ -0,0 +1,37 @@
+import { Canvas, Meta, Source, Subtitle, Title } from "@storybook/blocks";
+
+import * as stories from "./card.stories";
+
+
+
+
+
+ A card is used to display content and actions on a single topic. They provide a flexible and extensible content container that groups related information in an easily scannable format.
+
+
+## How to get started
+Start by importing the component. Once imported, the `` component is ready to use.
+``` ts
+// Web component
+import '@computas/designsystem/card';
+
+// React
+import { CxCard } from '@computas/designsystem/card/react';
+```
+
+## Default
+A card can consist of an **image**, **title**, **subtitle** and **body content**. The **title** and **image** can be set as properties, while **subtitle** and **body** use slots for maximum flexibility.
+
+
+## Content slots
+The card supports several content slots for customization:
+
+- **`subtitle`** - For metadata like time, location, or categories
+- **`body`** - For additional content like buttons, tags, or other actions
+
+
+ 14:00 - 16:00 • Oslo, Norway
+ Learn more
+ `}
+/>
\ No newline at end of file
diff --git a/packages/lib/components/card/card.stories.ts b/packages/lib/components/card/card.stories.ts
new file mode 100644
index 0000000..c23f181
--- /dev/null
+++ b/packages/lib/components/card/card.stories.ts
@@ -0,0 +1,33 @@
+import type { Meta, StoryObj } from '@storybook/web-components';
+import { html } from 'lit';
+import './card.js';
+
+const meta: Meta = {
+ title: 'Components/Card',
+ component: 'cx-card',
+ parameters: {
+ layout: 'centered',
+ },
+ argTypes: {
+ title: { control: 'text' },
+ image: { control: 'text' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ title: 'Card Title',
+ image: 'https://picsum.photos/500/220',
+ },
+ render: (args) => html`
+
+ 14:00 - 16:00 • Oslo, Norway
+
+
Additional body content
+
+
+ `,
+};
diff --git a/packages/lib/components/card/card.ts b/packages/lib/components/card/card.ts
new file mode 100644
index 0000000..9c49917
--- /dev/null
+++ b/packages/lib/components/card/card.ts
@@ -0,0 +1,153 @@
+import { LitElement, css, html, unsafeCSS } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+import text1CSS from '../../global-css/typography/text-1.css?inline';
+import text4CSS from '../../global-css/typography/text-4.css?inline';
+
+@customElement('cx-card')
+export class Card extends LitElement {
+ static styles = [
+ unsafeCSS(text1CSS),
+ unsafeCSS(text4CSS),
+ css`
+ .card {
+ position: relative;
+ height: 100%;
+ width: 100%;
+ border-radius: 24px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ text-decoration: none;
+ color: inherit;
+ }
+
+ .card-image {
+ width: 100%;
+ height: 192px;
+ position: relative;
+ flex-shrink: 0;
+ }
+
+ .card-image img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ transition: filter 0.3s ease;
+ }
+
+ /* Blue filter on img for hover */
+ .card-image::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ mix-blend-mode: multiply;
+ background: var(--cx-color-background-accent-5);
+ opacity: 0;
+ transition: opacity 0.3s ease;
+ }
+
+ .card-info {
+ flex: 1;
+ padding: var(--cx-spacing-6);
+ color: var(--cx-color-text-primary);
+ background-color: var(--cx-color-background-accent-1-soft);
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ box-sizing: border-box;
+ }
+
+ .card-subtitle {
+ display: flex;
+ flex-wrap: wrap;
+ color: var(--cx-color-text-less-important);
+ gap: var(--cx-spacing-2);
+ margin-bottom: var(--cx-spacing-4);
+ }
+
+ .card-title {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ overflow: hidden;
+ margin-bottom: var(--cx-spacing-2);
+ align-content: center;
+ }
+
+ .card-body {
+ display: flex;
+ gap: var(--cx-spacing-2);
+ flex-wrap: wrap;
+ margin-top: auto;
+ }
+
+ /* Hover effects - only on image */
+ .card:hover .card-image img {
+ filter: grayscale(1);
+ }
+
+ .card:hover .card-image::after {
+ opacity: 1;
+ }
+
+ @media (max-width: 750px) {
+ .card {
+ flex-direction: column;
+ height: auto;
+ }
+
+ .card-image {
+ width: 100%;
+ height: 125px;
+ }
+
+ .card-info {
+ width: 100%;
+ padding: var(--cx-spacing-4);
+ flex-direction: column-reverse;
+ gap: var(--cx-spacing-2);
+ box-sizing: border-box;
+ }
+ }
+`,
+ ];
+
+ @property({ type: String, reflect: true })
+ title = '';
+
+ @property({ type: String, reflect: true })
+ image = '';
+
+ render() {
+ return html`
+
+
+ ${this.image ? html`
` : html`
`}
+
+
+
+
+
+ ${
+ this.title
+ ? html`
${this.title}
`
+ : html`
`
+ }
+
+
+
+
+
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'cx-card': Card;
+ }
+}
diff --git a/packages/lib/global-css/typography.css b/packages/lib/global-css/typography.css
index 04164d3..785e3eb 100644
--- a/packages/lib/global-css/typography.css
+++ b/packages/lib/global-css/typography.css
@@ -11,152 +11,6 @@ button {
font-family: inherit;
}
-.cx-title-1,
-.cx-title-2,
-.cx-title-3,
-.cx-title-4,
-.cx-title-5 {
- text-wrap: balance;
-}
-
-.cx-title-1 {
- font-weight: 400;
- font-size: 2.75rem;
- line-height: 1.6;
-}
-
-.cx-title-2 {
- font-weight: 600;
- font-size: 2.25rem;
- line-height: 1.6;
-}
-
-.cx-title-3 {
- font-weight: 600;
- font-size: 1.75rem;
- line-height: 1.6;
-}
-
-.cx-title-4 {
- font-weight: 600;
- font-size: 1.5rem;
- line-height: 1.6;
-}
-
-.cx-title-5 {
- font-weight: 600;
- font-size: 1.125rem;
- line-height: 1.125;
-}
-
-:is(p):where(.cx-text-1, .cx-text-2, .cx-text-3, .cx-text-4, .cx-text-micro) {
- max-width: 65ch;
- text-wrap: pretty;
- word-break: auto-phrase;
-}
-
-.cx-text-1 {
- font-weight: 400;
- font-size: 1.5rem;
- line-height: 1.6;
-}
-
-.cx-text-2 {
- font-weight: 400;
- font-size: 1.125rem;
- line-height: 1.6;
-}
-
-.cx-text-2-strong {
- font-weight: 600;
- font-size: 1.125rem;
- line-height: 1.6;
-}
-
-.cx-text-2-light {
- font-weight: 300;
- font-size: 1.125rem;
- line-height: 1.6;
-}
-
-.cx-text-3 {
- font-weight: 400;
- font-size: 1rem;
- line-height: 1.6;
-}
-
-.cx-text-3-strong {
- font-weight: 600;
- font-size: 1rem;
- line-height: 1.6;
-}
-
-.cx-text-3-light {
- font-weight: 300;
- font-size: 1rem;
- line-height: 1.6;
-}
-
-.cx-text-4 {
- font-weight: 400;
- font-size: 0.875rem;
- line-height: 1.6;
-}
-
-.cx-text-4-strong {
- font-weight: 600;
- font-size: 0.875rem;
- line-height: 1.6;
-}
-
-.cx-text-4-light {
- font-weight: 300;
- font-size: 0.875rem;
- line-height: 1.6;
-}
-
-.cx-text-jumbo {
- font-weight: 700;
- font-size: 3.75rem;
- line-height: 1.6;
-}
-
-.cx-text-jumbo-mobile {
- font-weight: 700;
- font-size: 2rem;
- line-height: 1.4;
-}
-
-.cx-text-micro {
- font-weight: 400;
- font-size: 0.75rem;
- line-height: 1.6;
-}
-
-.cx-text-micro-strong {
- font-weight: 600;
- font-size: 0.75rem;
- line-height: 1.6;
-}
-
-.cx-text-clickable-1 {
- font-weight: 500;
- font-size: 1.125rem;
- line-height: 1;
-}
-
-.cx-text-clickable-2 {
- font-weight: 500;
- font-size: 1rem;
- line-height: 1;
-}
-
-.cx-text-clickable-3 {
- font-weight: 500;
- font-size: 0.875rem;
- line-height: 1;
-}
-
.cx-overflow-ellipsis {
white-space: nowrap;
text-overflow: ellipsis;
diff --git a/packages/lib/global-css/typography/text-1.css b/packages/lib/global-css/typography/text-1.css
new file mode 100644
index 0000000..d064f19
--- /dev/null
+++ b/packages/lib/global-css/typography/text-1.css
@@ -0,0 +1,17 @@
+.cx-text-1 {
+ font-size: 1.5rem;
+ font-weight: 400;
+ line-height: 1.6;
+}
+
+:is(p).cx-text-1 {
+ max-width: 65ch;
+ text-wrap: pretty;
+ word-break: auto-phrase;
+}
+
+.cx-text-clickable-1 {
+ font-weight: 500;
+ font-size: 1.125rem;
+ line-height: 1;
+}
diff --git a/packages/lib/global-css/typography/text-2.css b/packages/lib/global-css/typography/text-2.css
new file mode 100644
index 0000000..455721b
--- /dev/null
+++ b/packages/lib/global-css/typography/text-2.css
@@ -0,0 +1,29 @@
+.cx-text-2 {
+ font-size: 1.125rem;
+ font-weight: 400;
+ line-height: 1.6;
+}
+
+:is(p).cx-text-2 {
+ max-width: 65ch;
+ text-wrap: pretty;
+ word-break: auto-phrase;
+}
+
+.cx-text-2-strong {
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+.cx-text-2-light {
+ font-weight: 300;
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+.cx-text-clickable-2 {
+ font-weight: 500;
+ font-size: 1rem;
+ line-height: 1;
+}
diff --git a/packages/lib/global-css/typography/text-3.css b/packages/lib/global-css/typography/text-3.css
new file mode 100644
index 0000000..b20722f
--- /dev/null
+++ b/packages/lib/global-css/typography/text-3.css
@@ -0,0 +1,29 @@
+.cx-text-3 {
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.6;
+}
+
+:is(p).cx-text-3 {
+ max-width: 65ch;
+ text-wrap: pretty;
+ word-break: auto-phrase;
+}
+
+.cx-text-3-strong {
+ font-weight: 600;
+ font-size: 1rem;
+ line-height: 1.6;
+}
+
+.cx-text-3-light {
+ font-weight: 300;
+ font-size: 1rem;
+ line-height: 1.6;
+}
+
+.cx-text-clickable-3 {
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1;
+}
diff --git a/packages/lib/global-css/typography/text-4.css b/packages/lib/global-css/typography/text-4.css
new file mode 100644
index 0000000..24e6ff5
--- /dev/null
+++ b/packages/lib/global-css/typography/text-4.css
@@ -0,0 +1,23 @@
+.cx-text-4 {
+ font-size: 0.875rem;
+ font-weight: 400;
+ line-height: 1.6;
+}
+
+:is(p).cx-text-4 {
+ max-width: 65ch;
+ text-wrap: pretty;
+ word-break: auto-phrase;
+}
+
+.cx-text-4-strong {
+ font-weight: 600;
+ font-size: 0.875rem;
+ line-height: 1.6;
+}
+
+.cx-text-4-light {
+ font-weight: 300;
+ font-size: 0.875rem;
+ line-height: 1.6;
+}
diff --git a/packages/lib/global-css/typography/text-jumbo.css b/packages/lib/global-css/typography/text-jumbo.css
new file mode 100644
index 0000000..88ec97b
--- /dev/null
+++ b/packages/lib/global-css/typography/text-jumbo.css
@@ -0,0 +1,11 @@
+.cx-text-jumbo {
+ font-weight: 700;
+ font-size: 3.75rem;
+ line-height: 1.6;
+}
+
+.cx-text-jumbo-mobile {
+ font-weight: 700;
+ font-size: 2rem;
+ line-height: 1.4;
+}
diff --git a/packages/lib/global-css/typography/text-micro.css b/packages/lib/global-css/typography/text-micro.css
new file mode 100644
index 0000000..5557763
--- /dev/null
+++ b/packages/lib/global-css/typography/text-micro.css
@@ -0,0 +1,11 @@
+.cx-text-micro {
+ font-size: 0.75rem;
+ font-weight: 400;
+ line-height: 1.6;
+}
+
+:is(p).cx-text-micro {
+ max-width: 65ch;
+ text-wrap: pretty;
+ word-break: auto-phrase;
+}
diff --git a/packages/lib/global-css/typography/title-1.css b/packages/lib/global-css/typography/title-1.css
new file mode 100644
index 0000000..6ef86ab
--- /dev/null
+++ b/packages/lib/global-css/typography/title-1.css
@@ -0,0 +1,6 @@
+.cx-title-1 {
+ font-weight: 400;
+ font-size: 2.75rem;
+ line-height: 1.6;
+ text-wrap: balance;
+}
diff --git a/packages/lib/global-css/typography/title-2.css b/packages/lib/global-css/typography/title-2.css
new file mode 100644
index 0000000..f2822d4
--- /dev/null
+++ b/packages/lib/global-css/typography/title-2.css
@@ -0,0 +1,6 @@
+.cx-title-2 {
+ font-weight: 600;
+ font-size: 2.25rem;
+ line-height: 1.6;
+ text-wrap: balance;
+}
diff --git a/packages/lib/global-css/typography/title-3.css b/packages/lib/global-css/typography/title-3.css
new file mode 100644
index 0000000..7d86741
--- /dev/null
+++ b/packages/lib/global-css/typography/title-3.css
@@ -0,0 +1,6 @@
+.cx-title-3 {
+ font-weight: 600;
+ font-size: 1.75rem;
+ line-height: 1.6;
+ text-wrap: balance;
+}
diff --git a/packages/lib/global-css/typography/title-4.css b/packages/lib/global-css/typography/title-4.css
new file mode 100644
index 0000000..04954ee
--- /dev/null
+++ b/packages/lib/global-css/typography/title-4.css
@@ -0,0 +1,6 @@
+.cx-title-4 {
+ font-weight: 600;
+ font-size: 1.5rem;
+ line-height: 1.6;
+ text-wrap: balance;
+}
diff --git a/packages/lib/global-css/typography/title-5.css b/packages/lib/global-css/typography/title-5.css
new file mode 100644
index 0000000..649db25
--- /dev/null
+++ b/packages/lib/global-css/typography/title-5.css
@@ -0,0 +1,6 @@
+.cx-title-5 {
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.125;
+ text-wrap: balance;
+}
diff --git a/packages/lib/global-styles.css b/packages/lib/global-styles.css
index d537c55..eaff636 100644
--- a/packages/lib/global-styles.css
+++ b/packages/lib/global-styles.css
@@ -13,6 +13,16 @@
@import "global-css/a11y.css";
@import "global-css/margins.css";
@import "global-css/typography.css";
+@import "global-css/typography/title-1.css";
+@import "global-css/typography/title-2.css";
+@import "global-css/typography/title-3.css";
+@import "global-css/typography/title-4.css";
+@import "global-css/typography/title-5.css";
+@import "global-css/typography/text-1.css";
+@import "global-css/typography/text-2.css";
+@import "global-css/typography/text-3.css";
+@import "global-css/typography/text-4.css";
+@import "global-css/typography/text-micro.css";
@import "global-css/animations.css";
/* Components */