08 — Apps

Authentication

Layout shells for sign in, sign up, password recovery, and a two-factor code step. Wire forms to your backend; markup and classes are presentation-only.

Sign in

downstage

Sign in

Use your work email and password.

<div class="auth-shell">
  <div class="auth-card auth-card-wide">
    <div class="auth-brand">
      <svg class="icon icon-lg" aria-hidden="true"><use href="downstage-icons.svg#hash" /></svg>
      Brand
    </div>
    <h3 class="auth-title">Sign in</h3>
    <p class="auth-subtitle">Use your work email and password.</p>
    <form class="auth-form" action="#" method="post">
      <div class="field">
        <label class="label">Email</label>
        <input class="input" type="email" name="email" autocomplete="username" required>
      </div>
      <div class="field">
        <label class="label">Password</label>
        <input class="input" type="password" name="password" autocomplete="current-password" required>
      </div>
      <div class="auth-links-row">
        <label class="check">
          <input type="checkbox" name="remember">
          <span>Remember me</span>
        </label>
        <a href="#">Forgot password?</a>
      </div>
      <div class="auth-actions">
        <button type="submit" class="btn btn-primary btn-block">Sign in</button>
      </div>
    </form>
    <div class="auth-footer">
      No account? <a href="#">Create one</a>
    </div>
  </div>
</div>

Sign up

Create account

Sign up with your email. We will send a verification link.

At least 8 characters.
<div class="auth-shell">
  <div class="auth-card auth-card-wide">
    <h3 class="auth-title">Create account</h3>
    <p class="auth-subtitle">Sign up with your email.</p>
    <form class="auth-form" action="#" method="post">
      <div class="field">
        <label class="label">Full name</label>
        <input class="input" type="text" name="name" autocomplete="name" required>
      </div>
      <div class="field">
        <label class="label">Email</label>
        <input class="input" type="email" name="email" autocomplete="email" required>
      </div>
      <div class="field">
        <label class="label">Password</label>
        <input class="input" type="password" name="password" autocomplete="new-password" required minlength="8">
        <span class="help">At least 8 characters.</span>
      </div>
      <label class="check">
        <input type="checkbox" name="terms" required>
        <span>I agree to the terms and privacy policy</span>
      </label>
      <div class="auth-actions">
        <button type="submit" class="btn btn-primary btn-block">Sign up</button>
      </div>
    </form>
    <div class="auth-footer">
      Already have an account? <a href="#">Sign in</a>
    </div>
  </div>
</div>

Reset password

Reset password

Enter your email and we will send reset instructions.

Back to sign in
<div class="auth-shell">
  <div class="auth-card">
    <h3 class="auth-title">Reset password</h3>
    <p class="auth-subtitle">Enter your email and we will send reset instructions.</p>
    <form class="auth-form" action="#" method="post">
      <div class="field">
        <label class="label">Email</label>
        <input class="input" type="email" name="email" autocomplete="email" required>
      </div>
      <div class="auth-actions">
        <button type="submit" class="btn btn-primary btn-block">Send reset link</button>
        <a href="#" class="btn btn-ghost btn-block">Back to sign in</a>
      </div>
    </form>
  </div>
</div>

Two-factor authentication

Two-factor authentication

Enter the 6-digit code from your authenticator app.

Alternatively, use a backup code in the field below.

<div class="auth-shell">
  <div class="auth-card">
    <h3 class="auth-title">Two-factor authentication</h3>
    <p class="auth-subtitle">Enter the 6-digit code from your authenticator app.</p>
    <form class="auth-form" action="#" method="post">
      <div class="auth-otp" role="group" aria-label="One-time code">
        <input class="input" type="text" inputmode="numeric" maxlength="1" aria-label="Digit 1">
        <input class="input" type="text" inputmode="numeric" maxlength="1" aria-label="Digit 2">
        <input class="input" type="text" inputmode="numeric" maxlength="1" aria-label="Digit 3">
        <input class="input" type="text" inputmode="numeric" maxlength="1" aria-label="Digit 4">
        <input class="input" type="text" inputmode="numeric" maxlength="1" aria-label="Digit 5">
        <input class="input" type="text" inputmode="numeric" maxlength="1" aria-label="Digit 6">
      </div>
      <p class="help text-center">Alternatively, use a backup code below.</p>
      <div class="field">
        <label class="label">Backup code</label>
        <input class="input" type="text" name="backup" placeholder="XXXX-XXXX">
      </div>
      <div class="auth-actions">
        <button type="submit" class="btn btn-primary btn-block">Verify</button>
      </div>
    </form>
  </div>
</div>

20 — Data

Dashboard

Stat cards and minimal SVG charts for data-driven UIs.

Revenue
$48.2k
+12.5%
Users
2,847
+8.1%
Bounce rate
24.6%
-3.2%
Traffic overview
Last 12 months
Visitors
Sources
This month
73% organic
Direct Organic Referral
Monthly performance
Revenue per month (K)
<!-- Stat cards -->
<div class="dashboard-grid">
  <div class="stat-card">
    <div class="stat-label">Revenue</div>
    <div class="stat-value">$48.2k</div>
    <div class="stat-change is-up">
      <svg class="icon icon-sm"><use href="downstage-icons.svg#trending-up" /></svg>
      +12.5%
    </div>
  </div>
  <!-- repeat .stat-card for each metric -->
</div>

<!-- Charts row: line + donut -->
<div class="grid mt-6">
  <div class="col-8">
    <div class="chart-card">
      <div class="chart-header">
        <div>
          <div class="chart-title">Traffic overview</div>
          <div class="chart-subtitle">Last 12 months</div>
        </div>
      </div>
      <div class="chart-canvas">
        <svg class="chart-line-svg" viewBox="0 0 400 160" preserveAspectRatio="none">
          <path class="chart-line-area" d="M0,120 L100,80 L200,70 L300,30 L400,35 L400,160 L0,160Z" />
          <path class="chart-line-path" d="M0,120 L100,80 L200,70 L300,30 L400,35" />
        </svg>
      </div>
      <div class="chart-legend">
        <span class="chart-legend-item"><span class="chart-legend-dot"></span> Visitors</span>
      </div>
    </div>
  </div>
  <div class="col-4">
    <div class="chart-card">
      <div class="chart-header">
        <div>
          <div class="chart-title">Sources</div>
          <div class="chart-subtitle">This month</div>
        </div>
      </div>
      <div class="chart-canvas">
        <svg class="chart-donut-svg" viewBox="0 0 120 120">
          <circle class="chart-donut-ring" cx="60" cy="60" r="48" stroke="var(--text)" stroke-dasharray="180 302" />
          <circle class="chart-donut-ring" cx="60" cy="60" r="48" stroke="var(--brand-primary)" stroke-dasharray="90 302" />
          <text class="chart-donut-center" x="60" y="57">73%</text>
          <text class="chart-donut-label" x="60" y="74">organic</text>
        </svg>
      </div>
    </div>
  </div>
</div>

<!-- Bar chart -->
<div class="chart-card mt-6">
  <div class="chart-header">
    <div>
      <div class="chart-title">Monthly performance</div>
      <div class="chart-subtitle">Revenue per month (K)</div>
    </div>
  </div>
  <div class="chart-canvas">
    <div class="chart-bar-group">
      <div class="chart-bar" style="height:40%"></div>
      <div class="chart-bar" style="height:65%"></div>
      <div class="chart-bar is-accent" style="height:90%"></div>
      <!-- repeat for each month -->
    </div>
  </div>
</div>

21 — Components

Portfolio

Project cards in a responsive grid. Use .portfolio-item as a block or wrap the whole card in <a>. Optional .portfolio-item--featured spans two columns on wide viewports.

<div class="portfolio">
  <!-- Featured item spans two columns -->
  <a href="#" class="portfolio-item portfolio-item--featured">
    <div class="portfolio-media">
      <img src="project-hero.jpg" alt="Project preview">
    </div>
    <div class="portfolio-body">
      <span class="portfolio-meta">Product &middot; 2025</span>
      <h3 class="portfolio-title">Project name</h3>
      <p class="portfolio-desc">Short description of the project.</p>
      <div class="portfolio-tags">
        <span class="badge">UI</span>
        <span class="badge badge-info">React</span>
      </div>
    </div>
    <div class="portfolio-footer">
      <span class="text-subtle text-sm">Case study</span>
      <span class="portfolio-link">
        View
        <svg class="icon" aria-hidden="true"><use href="downstage-icons.svg#arrow-right" /></svg>
      </span>
    </div>
  </a>

  <!-- Standard item -->
  <a href="#" class="portfolio-item">
    <div class="portfolio-media">
      <img src="project-thumb.jpg" alt="Project preview">
    </div>
    <div class="portfolio-body">
      <span class="portfolio-meta">Web &middot; 2024</span>
      <h3 class="portfolio-title">Another project</h3>
      <p class="portfolio-desc">Brief project summary.</p>
    </div>
    <div class="portfolio-footer">
      <span class="text-subtle text-sm">Category</span>
      <span class="portfolio-link">
        View
        <svg class="icon" aria-hidden="true"><use href="downstage-icons.svg#arrow-right" /></svg>
      </span>
    </div>
  </a>
</div>

Minimal

Compact variant on --bg: horizontal rules only, no card chrome — same idea as .table-minimal and .input-minimal. Use .portfolio.portfolio--minimal and .portfolio-item--minimal.

<div class="portfolio portfolio--minimal">
  <a href="#" class="portfolio-item portfolio-item--minimal">
    <div class="portfolio-media">
      <img src="project-thumb.jpg" alt="Project preview">
    </div>
    <div class="portfolio-body">
      <span class="portfolio-meta">Category &middot; 2025</span>
      <h3 class="portfolio-title">Project name</h3>
      <p class="portfolio-desc">Short description.</p>
      <div class="portfolio-tags">
        <span class="badge">Tag</span>
      </div>
    </div>
    <div class="portfolio-footer">
      <span class="text-subtle text-sm">Type</span>
      <span class="portfolio-link">
        View
        <svg class="icon" aria-hidden="true"><use href="downstage-icons.svg#arrow-right" /></svg>
      </span>
    </div>
  </a>
</div>

22 — Components

Blog

Article teasers with .blog-card inside .blog-list--grid or a vertical .blog-list. Meta line supports date, category, and reading time.

<div class="blog-list blog-list--grid">
  <a href="#" class="blog-card">
    <div class="blog-card-media">
      <img src="post-cover.jpg" alt="Post cover">
    </div>
    <div class="blog-card-body">
      <div class="blog-card-meta">
        <time datetime="2026-03-12">12 Mar 2026</time>
        <span class="badge badge-info">Tutorial</span>
        <span>6 min read</span>
      </div>
      <h3 class="blog-card-title">Article title</h3>
      <p class="blog-card-excerpt">Short excerpt or summary.</p>
      <div class="blog-card-footer">
        <span class="text-subtle text-sm">Author</span>
        <span class="blog-read-more">
          Read
          <svg class="icon" aria-hidden="true"><use href="downstage-icons.svg#arrow-right" /></svg>
        </span>
      </div>
    </div>
  </a>
  <!-- repeat .blog-card -->
</div>

Stacked list

Same card pattern in a vertical .blog-list for archive pages.

<div class="blog-list blog-list--narrow">
  <a href="#" class="blog-card blog-card--compact">
    <div class="blog-card-body">
      <div class="blog-card-meta">
        <time datetime="2025-11-02">2 Nov 2025</time>
        <span class="badge badge-warning">Draft</span>
      </div>
      <h3 class="blog-card-title">Article title</h3>
      <p class="blog-card-excerpt">Short excerpt.</p>
      <div class="blog-card-footer">
        <span class="text-subtle text-sm">Category</span>
        <span class="blog-read-more">
          Read
          <svg class="icon" aria-hidden="true"><use href="downstage-icons.svg#arrow-right" /></svg>
        </span>
      </div>
    </div>
  </a>
  <!-- repeat .blog-card.blog-card--compact -->
</div>

Minimal

List with .blog-list--minimal and .blog-card--minimal: thumbnail on the left (on wide viewports), no heavy shadow or full border.

<div class="blog-list blog-list--grid blog-list--minimal">
  <a href="#" class="blog-card blog-card--minimal">
    <div class="blog-card-media">
      <img src="thumb.jpg" alt="Post thumbnail">
    </div>
    <div class="blog-card-body">
      <div class="blog-card-meta">
        <time datetime="2026-04-01">1 Apr 2026</time>
        <span class="badge">Notes</span>
        <span>4 min</span>
      </div>
      <h3 class="blog-card-title">Article title</h3>
      <p class="blog-card-excerpt">Short excerpt.</p>
      <div class="blog-card-footer">
        <span class="text-subtle text-sm">Category</span>
        <span class="blog-read-more">
          Read
          <svg class="icon" aria-hidden="true"><use href="downstage-icons.svg#arrow-right" /></svg>
        </span>
      </div>
    </div>
  </a>
  <!-- repeat .blog-card.blog-card--minimal -->
</div>

24 — Components

About me

Profile block with photo, role line, bio, and social icons. Markup uses .about, .about-media, and .about-content.

Portrait of John Doe

John Doe

Designer & developer · Bergamo, Italy

I build calm interfaces and design systems that stay out of the way. downstage.css is a small, token-driven toolkit for sites and apps that value clarity over noise — Nordic-inspired restraint, no build step required.

When I'm not shipping UI, I'm probably refining typography, hiking, or chasing good espresso.

<div class="about">
  <div class="about-media">
    <img src="portrait.jpg" alt="Portrait">
  </div>
  <div class="about-content">
    <header>
      <h3 class="about-name">John Doe</h3>
      <p class="about-role">Designer &amp; developer</p>
    </header>
    <p class="about-bio">Bio paragraph.</p>
    <div class="about-social" aria-label="Social profiles">
      <a href="#" aria-label="Website">
        <svg class="icon"><use href="downstage-icons.svg#globe" /></svg>
      </a>
      <a href="#" aria-label="GitHub">
        <svg class="icon"><use href="downstage-icons.svg#github" /></svg>
      </a>
      <a href="#" aria-label="Email">
        <svg class="icon"><use href="downstage-icons.svg#mail" /></svg>
      </a>
    </div>
  </div>
</div>

25 — Components

Team

People grid with photo, role, and short bio. Classes: .team-grid, .team-card, .team-avatar, .team-name, .team-role, .team-bio, optional .team-links.

Portrait of John Doe

John Doe

Founder & design system

Owns downstage.css, tokens, and docs. Calm interfaces, clean code.

Portrait of Elena Rossi

Emily Smith

Product design

Wireframes, prototypes, and accessibility. Keeps components and real pages aligned.

<div class="team-grid">
  <article class="team-card">
    <div class="team-avatar">
      <img src="avatar.jpg" alt="Portrait">
    </div>
    <h3 class="team-name">John Doe</h3>
    <p class="team-role">Role title</p>
    <p class="team-bio">Short bio text.</p>
    <div class="team-links" aria-label="Profile links">
      <a href="#" aria-label="Website">
        <svg class="icon"><use href="downstage-icons.svg#globe" /></svg>
      </a>
      <a href="#" aria-label="GitHub">
        <svg class="icon"><use href="downstage-icons.svg#github" /></svg>
      </a>
    </div>
  </article>
  <!-- repeat .team-card -->
</div>

27 — Components

Shop

Mini e-commerce patterns: product grid, product page, cart rows, and payment step. Markup and CSS only — wire logic to your backend or payment provider.

List

<div class="shop-grid">
  <article class="shop-card">
    <a href="#" class="shop-card-hit" aria-label="Product — view">
      <div class="shop-card-media">
        <span class="shop-card-badge"><span class="badge badge-success">New</span></span>
        <img src="product.jpg" alt="Product photo">
      </div>
      <div class="shop-card-body">
        <p class="shop-card-meta">Category</p>
        <h3 class="shop-card-title">Product name</h3>
        <p><span class="shop-price">&euro;24,00</span></p>
      </div>
    </a>
    <div class="shop-card-footer">
      <span class="text-subtle text-sm">Variant</span>
      <button type="button" class="btn btn-sm btn-primary">Add</button>
    </div>
  </article>
  <!-- repeat .shop-card -->
</div>

Minimal

Compact grid with .shop-grid--minimal and .shop-card--minimal: horizontal rows like a light table.

<div class="shop-grid shop-grid--minimal">
  <article class="shop-card shop-card--minimal">
    <a href="#" class="shop-card-hit" aria-label="Product — view">
      <div class="shop-card-media">
        <img src="product-thumb.jpg" alt="Product photo">
      </div>
      <div class="shop-card-body">
        <p class="shop-card-meta">Category</p>
        <h3 class="shop-card-title">Product name</h3>
        <p><span class="shop-price">&euro;32,00</span></p>
      </div>
    </a>
    <div class="shop-card-footer">
      <span class="text-subtle text-sm">Variant</span>
      <button type="button" class="btn btn-sm btn-primary">Add</button>
    </div>
  </article>
  <!-- repeat .shop-card.shop-card--minimal -->
</div>

Detail

Tableware · SKU DS-MUG-01

Mug Sand

Glazed stoneware, comfortable grip, matte finish that resists fingerprints.

€24,00 In stock · ships in 2 days

Free returns within 30 days. VAT included for EU.

<div class="product-detail">
  <div class="product-gallery">
    <img src="product-large.jpg" alt="Product detail">
  </div>
  <div class="product-info">
    <p class="text-subtle text-sm">Category &middot; SKU</p>
    <h3 class="product-title">Product name</h3>
    <p class="product-lead">Product description.</p>
    <div class="product-price-row">
      <span class="shop-price">&euro;24,00</span>
      <span class="text-subtle text-sm">In stock</span>
    </div>
    <div class="product-actions">
      <label class="text-sm text-muted">Qty</label>
      <input class="input shop-qty-input" type="number" value="1" min="1" max="99">
      <button type="button" class="btn btn-primary">
        <svg class="icon"><use href="downstage-icons.svg#shopping-cart" /></svg>
        Add to cart
      </button>
    </div>
    <p class="help">Free returns within 30 days.</p>
  </div>
</div>

Cart

Mug Sand

Mug Sand

Tableware · €24,00 each

€48,00
Throw Fog

Throw Fog

Home · €89,00 each

€89,00

Order summary

Subtotal €137,00
Shipping €6,00
Total €143,00
<div class="grid">
  <div class="col-8">
    <div class="cart" role="group" aria-label="Shopping cart">
      <div class="cart-row">
        <div class="cart-thumb">
          <img src="product-thumb.jpg" alt="Product">
        </div>
        <div class="cart-line-main">
          <p class="cart-line-title">Product name</p>
          <p class="cart-line-meta">Category &middot; &euro;24,00 each</p>
        </div>
        <div class="cart-line-end">
          <div class="cart-line-qty">
            <label class="sr-only">Quantity</label>
            <input class="input shop-qty-input" type="number" value="2" min="1" max="99">
          </div>
          <div class="cart-line-price">&euro;48,00</div>
        </div>
      </div>
      <!-- repeat .cart-row -->
    </div>
  </div>
  <div class="col-4">
    <div class="cart-summary">
      <p class="cart-summary-title">Order summary</p>
      <div class="cart-summary-row">
        <span>Subtotal</span><span>&euro;137,00</span>
      </div>
      <div class="cart-summary-row">
        <span>Shipping</span><span>&euro;6,00</span>
      </div>
      <div class="cart-summary-row cart-summary-row--total">
        <span>Total</span><span>&euro;143,00</span>
      </div>
      <button type="button" class="btn btn-primary btn-block mt-4">Checkout</button>
    </div>
  </div>
</div>

Payment

Payment

<div class="checkout-layout">
  <div class="payment-panel">
    <h3 class="payment-panel-title">Payment</h3>
    <form class="stack" action="#" method="post">
      <div class="field">
        <label class="label">Name on card</label>
        <input class="input" type="text" autocomplete="cc-name">
      </div>
      <div class="field">
        <label class="label">Card number</label>
        <input class="input" type="text" inputmode="numeric" autocomplete="cc-number">
      </div>
      <div class="payment-card-row">
        <div class="field">
          <label class="label">Expiry</label>
          <input class="input" type="text" autocomplete="cc-exp" placeholder="MM / YY">
        </div>
        <div class="field">
          <label class="label">CVC</label>
          <input class="input" type="text" autocomplete="cc-csc" placeholder="123">
        </div>
      </div>
      <button type="submit" class="btn btn-primary btn-block">Pay</button>
    </form>
  </div>
  <aside class="order-recap" aria-label="Order recap">
    <p class="order-recap-title">Your order</p>
    <div class="order-recap-item">
      <span>Item &times; 2</span><span>&euro;48,00</span>
    </div>
    <div class="order-recap-total">
      <span>Total</span><span>&euro;143,00</span>
    </div>
  </aside>
</div>

28 — Components

Profile

Account-area pattern: user fields, password, and security actions. Demo markup only — connect to real endpoints or your auth provider.

Account

Email and display name. Use .input-minimal for consistency with the rest of the page.

Password

Update your current password. In production, verify the current password on the server.

At least 12 characters; avoid passwords reused elsewhere.

Sessions

Revoke sessions on other devices after a password change or a suspicious sign-in.

<div class="profile-shell">
  <div class="profile-block">
    <h3 class="profile-block-title">Account</h3>
    <p class="profile-block-lead">Email and display name.</p>
    <form class="stack" action="#" method="post">
      <div class="field">
        <label class="label">Email</label>
        <input class="input input-minimal" type="email" autocomplete="email">
      </div>
      <div class="field">
        <label class="label">Display name</label>
        <input class="input input-minimal" type="text" autocomplete="name">
      </div>
      <div class="cluster mt-2" style="justify-content: flex-end;">
        <button type="button" class="btn btn-ghost">Discard</button>
        <button type="submit" class="btn btn-primary">Save changes</button>
      </div>
    </form>
  </div>

  <div class="profile-block">
    <h3 class="profile-block-title">Password</h3>
    <p class="profile-block-lead">Update your current password.</p>
    <form class="stack" action="#" method="post">
      <div class="field">
        <label class="label">Current password</label>
        <input class="input input-minimal" type="password" autocomplete="current-password">
      </div>
      <div class="field">
        <label class="label">New password</label>
        <input class="input input-minimal" type="password" autocomplete="new-password">
      </div>
      <div class="field">
        <label class="label">Confirm new password</label>
        <input class="input input-minimal" type="password" autocomplete="new-password">
      </div>
      <div class="cluster mt-2" style="justify-content: flex-end;">
        <button type="button" class="btn btn-secondary">Cancel</button>
        <button type="submit" class="btn btn-primary">Update password</button>
      </div>
    </form>
  </div>

  <div class="profile-block">
    <h3 class="profile-block-title">Sessions</h3>
    <p class="profile-block-lead">Revoke sessions on other devices.</p>
    <button type="button" class="btn btn-secondary btn-sm">Sign out everywhere</button>
  </div>
</div>