22 CSS Dark Mode UI14 / 22

Pure CSSMIT licensed

Cyber Terminal Dark UI Panel

A terminal panel with prompt history, streamed output and a live input line — phosphor green on black, a 2% scanline overlay and a blinking block caret. The retro reference is deliberate, the contrast is not: the green is tuned to 11:1 against the substrate, dim output still clears 4.5:1, and the whole CRT layer disappears under prefers-reduced-motion.

Published Updated

Live Demo
Try it

The code

<div class="dmu-14">
  <div class="dmu-14__stage">
    <section class="dmu-14__panel" aria-label="Terminal">
      <span class="dmu-14__crt" aria-hidden="true"></span>
      <header class="dmu-14__bar">
        <span class="dmu-14__dots" aria-hidden="true"><i></i><i></i><i></i></span>
        <p class="dmu-14__path">alex@meridian &mdash; ~/apps/web</p>
        <span class="dmu-14__status">
          <span class="dmu-14__led" aria-hidden="true"></span>
          connected
        </span>
      </header>

      <div class="dmu-14__scroll">
        <p class="dmu-14__line dmu-14__line--cmd">pnpm build --filter web</p>
        <p class="dmu-14__line dmu-14__line--out">Resolving 412 packages &hellip; done in 1.8s</p>
        <p class="dmu-14__line dmu-14__line--out">Compiled 96 routes with the edge runtime</p>
        <p class="dmu-14__line dmu-14__line--warn">theme.css: 3 selectors exceed specificity budget</p>
        <p class="dmu-14__line dmu-14__line--out">Bundle 184 kB gzip (&minus;12 kB from main)</p>
        <p class="dmu-14__line dmu-14__line--ok">Build succeeded in 14.2s</p>
        <p class="dmu-14__line dmu-14__line--cmd">node scripts/audit-contrast.mjs</p>
        <p class="dmu-14__line dmu-14__line--out">Checked 148 token pairs against WCAG AA</p>
        <p class="dmu-14__line dmu-14__line--ok">All pairs pass &mdash; lowest ratio 4.71:1</p>
      </div>

      <form class="dmu-14__prompt" onsubmit="return false">
        <label class="dmu-14__sr" for="dmu-14-input">Terminal command</label>
        <span class="dmu-14__sigil" aria-hidden="true">&#36;</span>
        <input class="dmu-14__input" id="dmu-14-input" type="text" autocomplete="off" spellcheck="false" placeholder="git switch -c theme/tokens">
        <span class="dmu-14__caret" aria-hidden="true"></span>
      </form>
    </section>
  </div>
</div>
.dmu-14 {
  --void: #04060a;
  --panel: #080c10;
  --bar: #0b1116;
  --hair: rgba(126,255,168,.16);
  --phosphor: #7effa8;
  --dim: #8fb7a0;
  --amber: #ffc866;
  --ok: #7effa8;
  --ink: #d8ffe6;
  --glow: rgba(126,255,168,.10);
  --rows: min(24rem,52vh);
  --mono: "JetBrains Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color-scheme: dark;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  background: radial-gradient(100% 70% at 50% 0%,#071016,var(--void) 70%),var(--void);
  color: var(--ink);
  font-family: var(--mono);
  -webkit-font-smoothing: antialiased;
}

.dmu-14,
.dmu-14 *,
.dmu-14 *::before,
.dmu-14 *::after {
  box-sizing: border-box;
}

.dmu-14__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.dmu-14__stage {
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(1rem,4vw,3rem);
}

.dmu-14__panel {
  position: relative;
  width: min(60rem,100%);
  overflow: hidden;
  border-radius: .9rem;
  background: var(--panel);
  border: 1px solid var(--hair);
  box-shadow: inset 0 0 60px var(--glow), 0 40px 80px -50px #000;
}

.dmu-14__crt {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: repeating-linear-gradient(180deg,rgba(255,255,255,.022) 0 1px,transparent 1px 3px), radial-gradient(120% 90% at 50% 50%,transparent 55%,rgba(0,0,0,.5));
}

.dmu-14__bar {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .6rem .85rem;
  background: var(--bar);
  border-bottom: 1px solid var(--hair);
}

.dmu-14__dots {
  display: flex;
  gap: .35rem;
}

.dmu-14__dots i {
  width: .6rem;
  height: .6rem;
  border-radius: 50%;
  background: rgba(126,255,168,.25);
}

.dmu-14__dots i:first-child {
  background: var(--phosphor);
}

.dmu-14__path {
  margin: 0;
  font-size: .74rem;
  color: var(--dim);
  letter-spacing: .02em;
}

.dmu-14__status {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .7rem;
  color: var(--dim);
}

.dmu-14__led {
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 8px var(--ok);
  animation: dmu-14-pulse 2.6s ease-in-out infinite;
}

@keyframes dmu-14-pulse {
  0%,
    100% {
    opacity: .55;
  }

  50% {
    opacity: 1;
  }
}

.dmu-14__scroll {
  display: grid;
  gap: .28rem;
  padding: 1rem 1.1rem;
  height: var(--rows);
  overflow: auto;
  align-content: start;
}

.dmu-14__line {
  margin: 0;
  display: grid;
  grid-template-columns: 1.1rem 1fr;
  gap: .5rem;
  font-size: .8rem;
  line-height: 1.55;
}

.dmu-14__line::before {
  color: var(--dim);
}

.dmu-14__line--cmd {
  color: var(--ink);
}

.dmu-14__line--cmd::before {
  content: '$';
  color: var(--phosphor);
}

.dmu-14__line--out {
  color: var(--dim);
}

.dmu-14__line--out::before {
  content: '\2192';
}

.dmu-14__line--warn {
  color: var(--amber);
}

.dmu-14__line--warn::before {
  content: '!';
  color: var(--amber);
}

.dmu-14__line--ok {
  color: var(--ok);
}

.dmu-14__line--ok::before {
  content: '\2713';
  color: var(--ok);
}

.dmu-14__prompt {
  position: relative;
  display: grid;
  grid-template-columns: 1.1rem 1fr;
  gap: .5rem;
  align-items: center;
  padding: .75rem 1.1rem;
  border-top: 1px solid var(--hair);
  background: var(--bar);
}

.dmu-14__sigil {
  color: var(--phosphor);
  font-size: .85rem;
}

.dmu-14__input {
  min-height: 2.1rem;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: .82rem;
  letter-spacing: .01em;
  caret-color: var(--phosphor);
}

.dmu-14__input::placeholder {
  color: color-mix(in oklab,var(--dim) 75%,transparent);
}

.dmu-14__input:focus {
  outline: none;
}

.dmu-14__prompt:focus-within {
  box-shadow: inset 0 0 0 1px color-mix(in oklab,var(--phosphor) 55%,transparent);
}

.dmu-14__caret {
  position: absolute;
  right: 1.1rem;
  width: .55rem;
  height: 1.05rem;
  background: var(--phosphor);
  animation: dmu-14-blink 1.05s steps(1,end) infinite;
}

.dmu-14__prompt:focus-within .dmu-14__caret {
  opacity: 0;
}

@keyframes dmu-14-blink {
  0%,
    49% {
    opacity: 1;
  }

  50%,
    100% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .dmu-14__caret,
    .dmu-14__led {
    animation: none;
  }

  .dmu-14__crt {
    background: radial-gradient(120% 90% at 50% 50%,transparent 60%,rgba(0,0,0,.4));
  }
}

@media (forced-colors: active) {
  .dmu-14__panel {
    border-color: CanvasText;
    box-shadow: none;
  }

  .dmu-14__crt {
    display: none;
  }

  .dmu-14__line,
    .dmu-14__line::before {
    color: CanvasText;
  }

  .dmu-14__caret {
    background: CanvasText;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Dark Mode UI from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Cyber Terminal Dark UI Panel
Source: https://codefronts.com/design-styles/css-dark-mode-ui/cyber-terminal/

A terminal panel with prompt history, streamed output and a live input line — phosphor green on black, a 2&percnt; scanline overlay and a blinking block caret. The retro reference is deliberate, the contrast is not: the green is tuned to 11:1 against the substrate, dim output still clears 4.5:1, and the whole CRT layer disappears under prefers-reduced-motion.
## HTML
```html
<div class="dmu-14">
  <div class="dmu-14__stage">
    <section class="dmu-14__panel" aria-label="Terminal">
      <span class="dmu-14__crt" aria-hidden="true"></span>
      <header class="dmu-14__bar">
        <span class="dmu-14__dots" aria-hidden="true"><i></i><i></i><i></i></span>
        <p class="dmu-14__path">alex@meridian &mdash; ~/apps/web</p>
        <span class="dmu-14__status">
          <span class="dmu-14__led" aria-hidden="true"></span>
          connected
        </span>
      </header>

      <div class="dmu-14__scroll">
        <p class="dmu-14__line dmu-14__line--cmd">pnpm build --filter web</p>
        <p class="dmu-14__line dmu-14__line--out">Resolving 412 packages &hellip; done in 1.8s</p>
        <p class="dmu-14__line dmu-14__line--out">Compiled 96 routes with the edge runtime</p>
        <p class="dmu-14__line dmu-14__line--warn">theme.css: 3 selectors exceed specificity budget</p>
        <p class="dmu-14__line dmu-14__line--out">Bundle 184 kB gzip (&minus;12 kB from main)</p>
        <p class="dmu-14__line dmu-14__line--ok">Build succeeded in 14.2s</p>
        <p class="dmu-14__line dmu-14__line--cmd">node scripts/audit-contrast.mjs</p>
        <p class="dmu-14__line dmu-14__line--out">Checked 148 token pairs against WCAG AA</p>
        <p class="dmu-14__line dmu-14__line--ok">All pairs pass &mdash; lowest ratio 4.71:1</p>
      </div>

      <form class="dmu-14__prompt" onsubmit="return false">
        <label class="dmu-14__sr" for="dmu-14-input">Terminal command</label>
        <span class="dmu-14__sigil" aria-hidden="true">&#36;</span>
        <input class="dmu-14__input" id="dmu-14-input" type="text" autocomplete="off" spellcheck="false" placeholder="git switch -c theme/tokens">
        <span class="dmu-14__caret" aria-hidden="true"></span>
      </form>
    </section>
  </div>
</div>
```
## CSS
```css
.dmu-14 {
  --void: #04060a;
  --panel: #080c10;
  --bar: #0b1116;
  --hair: rgba(126,255,168,.16);
  --phosphor: #7effa8;
  --dim: #8fb7a0;
  --amber: #ffc866;
  --ok: #7effa8;
  --ink: #d8ffe6;
  --glow: rgba(126,255,168,.10);
  --rows: min(24rem,52vh);
  --mono: "JetBrains Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color-scheme: dark;
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  background: radial-gradient(100% 70% at 50% 0%,#071016,var(--void) 70%),var(--void);
  color: var(--ink);
  font-family: var(--mono);
  -webkit-font-smoothing: antialiased;
}

.dmu-14,
.dmu-14 *,
.dmu-14 *::before,
.dmu-14 *::after {
  box-sizing: border-box;
}

.dmu-14__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.dmu-14__stage {
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(1rem,4vw,3rem);
}

.dmu-14__panel {
  position: relative;
  width: min(60rem,100%);
  overflow: hidden;
  border-radius: .9rem;
  background: var(--panel);
  border: 1px solid var(--hair);
  box-shadow: inset 0 0 60px var(--glow), 0 40px 80px -50px #000;
}

.dmu-14__crt {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: repeating-linear-gradient(180deg,rgba(255,255,255,.022) 0 1px,transparent 1px 3px), radial-gradient(120% 90% at 50% 50%,transparent 55%,rgba(0,0,0,.5));
}

.dmu-14__bar {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .6rem .85rem;
  background: var(--bar);
  border-bottom: 1px solid var(--hair);
}

.dmu-14__dots {
  display: flex;
  gap: .35rem;
}

.dmu-14__dots i {
  width: .6rem;
  height: .6rem;
  border-radius: 50%;
  background: rgba(126,255,168,.25);
}

.dmu-14__dots i:first-child {
  background: var(--phosphor);
}

.dmu-14__path {
  margin: 0;
  font-size: .74rem;
  color: var(--dim);
  letter-spacing: .02em;
}

.dmu-14__status {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .7rem;
  color: var(--dim);
}

.dmu-14__led {
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 8px var(--ok);
  animation: dmu-14-pulse 2.6s ease-in-out infinite;
}

@keyframes dmu-14-pulse {
  0%,
    100% {
    opacity: .55;
  }

  50% {
    opacity: 1;
  }
}

.dmu-14__scroll {
  display: grid;
  gap: .28rem;
  padding: 1rem 1.1rem;
  height: var(--rows);
  overflow: auto;
  align-content: start;
}

.dmu-14__line {
  margin: 0;
  display: grid;
  grid-template-columns: 1.1rem 1fr;
  gap: .5rem;
  font-size: .8rem;
  line-height: 1.55;
}

.dmu-14__line::before {
  color: var(--dim);
}

.dmu-14__line--cmd {
  color: var(--ink);
}

.dmu-14__line--cmd::before {
  content: '$';
  color: var(--phosphor);
}

.dmu-14__line--out {
  color: var(--dim);
}

.dmu-14__line--out::before {
  content: '\2192';
}

.dmu-14__line--warn {
  color: var(--amber);
}

.dmu-14__line--warn::before {
  content: '!';
  color: var(--amber);
}

.dmu-14__line--ok {
  color: var(--ok);
}

.dmu-14__line--ok::before {
  content: '\2713';
  color: var(--ok);
}

.dmu-14__prompt {
  position: relative;
  display: grid;
  grid-template-columns: 1.1rem 1fr;
  gap: .5rem;
  align-items: center;
  padding: .75rem 1.1rem;
  border-top: 1px solid var(--hair);
  background: var(--bar);
}

.dmu-14__sigil {
  color: var(--phosphor);
  font-size: .85rem;
}

.dmu-14__input {
  min-height: 2.1rem;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: .82rem;
  letter-spacing: .01em;
  caret-color: var(--phosphor);
}

.dmu-14__input::placeholder {
  color: color-mix(in oklab,var(--dim) 75%,transparent);
}

.dmu-14__input:focus {
  outline: none;
}

.dmu-14__prompt:focus-within {
  box-shadow: inset 0 0 0 1px color-mix(in oklab,var(--phosphor) 55%,transparent);
}

.dmu-14__caret {
  position: absolute;
  right: 1.1rem;
  width: .55rem;
  height: 1.05rem;
  background: var(--phosphor);
  animation: dmu-14-blink 1.05s steps(1,end) infinite;
}

.dmu-14__prompt:focus-within .dmu-14__caret {
  opacity: 0;
}

@keyframes dmu-14-blink {
  0%,
    49% {
    opacity: 1;
  }

  50%,
    100% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .dmu-14__caret,
    .dmu-14__led {
    animation: none;
  }

  .dmu-14__crt {
    background: radial-gradient(120% 90% at 50% 50%,transparent 60%,rgba(0,0,0,.4));
  }
}

@media (forced-colors: active) {
  .dmu-14__panel {
    border-color: CanvasText;
    box-shadow: none;
  }

  .dmu-14__crt {
    display: none;
  }

  .dmu-14__line,
    .dmu-14__line::before {
    color: CanvasText;
  }

  .dmu-14__caret {
    background: CanvasText;
  }
}
```

How this works

The scanline is one repeating gradient over the whole panel at very low opacity — cheap, and far more convincing than an image:

.dmu-14__crt{
  position:absolute; inset:0; pointer-events:none;
  background:repeating-linear-gradient(180deg,
    rgba(255,255,255,.02) 0 1px, transparent 1px 3px);
}

The caret is a pseudo-element with a stepped animation, so it snaps like a hardware cursor rather than fading like a CSS transition:

.dmu-14__caret{ animation:dmu-14-blink 1.05s steps(1,end) infinite; }
@keyframes dmu-14-blink{ 0%,49%{opacity:1} 50%,100%{opacity:0} }

Output lines use a status token pair rather than colour alone — each line carries a glyph ($, , !) so the meaning survives a monochrome screenshot or a colour-blind reader:

.dmu-14__line--warn{ color:var(--amber); }
.dmu-14__line--warn::before{ content:'!'; }

The panel glow is a single inset box-shadow in the accent hue at low alpha, which reads as emitted light without the cost of a blur filter.

Make it yours

  • Change --phosphor for a different tube: amber #ffb000, ice #7fd4ff, white #e8e8e8. Re-check contrast after switching hue.
  • Raise the scanline alpha to 4&percnt; for a heavier CRT read, or delete the overlay entirely for a modern terminal.
  • Add rows to the history by repeating a .dmu-14__line; the panel scrolls on its own and the prompt stays pinned.
  • Swap the block caret for an underline by changing its height and vertical alignment.
  • Widen the panel and set --rows higher for a log viewer rather than a shell.

Gotchas — read before shipping

  • Retro does not excuse low contrast. Classic phosphor green on black is often below 4.5:1 — the token here is lifted deliberately, and dim output text is a separate, audited token.
  • Scanlines interfere with subpixel text rendering. Keep them under 4&percnt; alpha and never animate their position under reduced-motion.
  • A blinking caret must stop for reduced-motion users; a permanently visible block is the correct fallback, not a hidden one.
  • Terminals are the easiest place to accidentally ship a <div> as an input. The prompt line here is a real <input> with a label, so it is focusable and typable.
  • Recommend <meta name="theme-color" content="#04060a"> for mobile, where the terminal usually fills the viewport.

Browser support

ChromeSafariFirefoxEdge
111+16.2+113+111+

Floor set by color-mix() as this demo is written. The core technique itself goes back further — Chrome 90+.

Repeating gradients, steps() animations and custom properties are universally supported. No :has() and no JavaScript, so the panel is safe in older embedded webviews too.

Techniques used in this demo

Search CodeFronts

Loading…