# Webcore

Pastel retro OS pieces: windows, dialogs, a joke captcha, buttons, form controls, block progress, a busy hourglass and pixel desktop icons\.

- Pieces: 9
- Credit: [Luna UI](https://thuvien.org/ui)
- Palette: [Webcore](https://thuvien.org/ui/colors/webcore.md): #F7B5E4 #A49BF3 #A445DD #2C2B9F #D9D9E5 #FFFFFF
- License: MIT

## Pieces

Each piece's page has its HTML, CSS and any variants or settings.

1. [Webcore window](https://thuvien.org/ui/elements/webcore-window.md) (element): Pastel retro OS window: dotted pink frame, title bar controls and a scrolling white page\.
2. [Webcore dialog](https://thuvien.org/ui/elements/webcore-dialog.md) (element): Retro OS alert box: coloured title bar, grey face, centred message and double\-ruled buttons\.
3. [Webcore captcha](https://thuvien.org/ui/elements/webcore-captcha.md) (element): Joke captcha dialog: a big tick box, a binary code field and yes or no keys in retro OS chrome\.
4. [Webcore message bar](https://thuvien.org/ui/elements/webcore-message.md) (element): Retro system message strip with a count and dismiss key; lilac, pink or plain with a speech bubble\.
5. [Webcore progress window](https://thuvien.org/ui/elements/webcore-progress.md) (element): Pastel pop\-up with a segmented block progress bar; set the fill with one CSS variable, or loop it\.
6. [Webcore hourglass](https://thuvien.org/ui/elements/webcore-hourglass.md) (element): Pixel hourglass busy indicator: the sand drains, the glass flips; optionally beside a pixel arrow cursor\.
7. [Webcore button](https://thuvien.org/ui/elements/webcore-button.md) (element): Retro OS push button with a hard drop shadow; pink, lilac, grey or double\-ruled default\.
8. [Webcore form controls](https://thuvien.org/ui/elements/webcore-form.md) (element): Retro OS text field, checkbox, radio buttons and dropdown on a grey or pink dialog face\.
9. [Webcore desktop icons](https://thuvien.org/ui/elements/webcore-icons.md) (element): Pixel desktop icons on a lavender desk: file, folder, book and program, with OS\-style selection\.

## Shared tokens

Custom properties every piece falls back from; set them once to restyle the kit.

```css
/* Webcore colours. Every piece falls back to these values, so set them once to restyle the kit. */
:root {
  --tv-webcore-pink: #f7b5e4;
  --tv-webcore-lilac: #a49bf3;
  --tv-webcore-violet: #a445dd;
  --tv-webcore-navy: #2c2b9f;
  --tv-webcore-grey: #d9d9e5;
  --tv-webcore-paper: #ffffff;
}
```

## Showcase

A scene that arranges the pieces together. It needs the pieces' CSS plus its own layout CSS.

```html
<div class="tv-webcore-scene">
  <div class="tv-webcore-scene-column tv-webcore-scene-side">
    <ul class="tv-webcore-icons">
      <li>
        <a class="tv-webcore-icon" href="#">
          <svg viewBox="0 0 16 16" aria-hidden="true">
            <path class="tv-webcore-icon-paper" d="M3.5 1.5h6l3 3v10h-9z" />
            <path class="tv-webcore-icon-pink" d="M9.5 1.5l3 3h-3z" />
            <path class="tv-webcore-icon-lilac" d="M5 12.5l2.5-3.5 1.5 2 1-1 1.5 2.5z" />
            <rect class="tv-webcore-icon-pink" x="5" y="6" width="2" height="2" />
            <path class="tv-webcore-icon-line" d="M3.5 1.5h6l3 3v10h-9zM9.5 1.5v3h3" />
          </svg>
          <span class="tv-webcore-icon-label">image.info</span>
        </a>
      </li>
      <li>
        <a class="tv-webcore-icon" href="#">
          <svg viewBox="0 0 16 16" aria-hidden="true">
            <path class="tv-webcore-icon-lilac" d="M1.5 3.5h5l1.5 1.5h6.5v9h-13z" />
            <path class="tv-webcore-icon-paper" d="M3 6h10v2H3z" />
            <path class="tv-webcore-icon-pink" d="M1.5 7.5h13v6h-13z" />
            <path class="tv-webcore-icon-line" d="M1.5 3.5h5l1.5 1.5h6.5v9h-13zM1.5 7.5h13" />
          </svg>
          <span class="tv-webcore-icon-label">folder</span>
        </a>
      </li>
      <li>
        <a class="tv-webcore-icon" href="#">
          <svg viewBox="0 0 16 16" aria-hidden="true">
            <path class="tv-webcore-icon-paper" d="M1.5 2.5h13v11h-13z" />
            <path class="tv-webcore-icon-violet" d="M1.5 2.5h13v3h-13z" />
            <rect class="tv-webcore-icon-paper" x="11" y="3" width="2" height="2" />
            <path class="tv-webcore-icon-lilac" d="M3 7h6v1H3zM3 9h8v1H3zM3 11h4v1H3z" />
            <path class="tv-webcore-icon-line" d="M1.5 2.5h13v11h-13zM1.5 5.5h13" />
          </svg>
          <span class="tv-webcore-icon-label">prgrm.py</span>
        </a>
      </li>
    </ul>
    <div class="tv-webcore-hourglass tv-webcore-hourglass--cursor" role="status">
      <svg class="tv-webcore-hourglass-cursor" viewBox="0 0 16 16" aria-hidden="true">
        <path class="tv-webcore-hourglass-paper" d="M1.5 1.5v12l3-3 2.5 4.5 2-1-2.5-4.5h4.5z" />
      </svg>
      <svg class="tv-webcore-hourglass-glass" viewBox="0 0 16 16" aria-hidden="true">
        <path class="tv-webcore-hourglass-paper" d="M4.5 3.5h7v2l-2.5 2.5 2.5 2.5v2h-7v-2l2.5-2.5-2.5-2.5z" />
        <path class="tv-webcore-hourglass-sand tv-webcore-hourglass-top" d="M5 4h6v1.5L8 7.5 5 5.5z" />
        <rect class="tv-webcore-hourglass-sand tv-webcore-hourglass-stream" x="7.5" y="7.5" width="1" height="4" />
        <path class="tv-webcore-hourglass-sand tv-webcore-hourglass-pile" d="M5 12h6v-1.5L8 8.5 5 10.5z" />
        <rect class="tv-webcore-hourglass-cap" x="3" y="1" width="10" height="2" />
        <rect class="tv-webcore-hourglass-cap" x="3" y="13" width="10" height="2" />
      </svg>
      <span class="tv-webcore-hourglass-label">loading…</span>
    </div>
  </div>
  <div class="tv-webcore-scene-column">
    <div class="tv-webcore-message" role="status">
      <span class="tv-webcore-message-text"><span class="tv-webcore-message-count">(3)</span> new guestbook entries</span>
      <svg class="tv-webcore-message-bubble" viewBox="0 0 32 20" aria-hidden="true"><path d="M4 1.5h24a2.5 2.5 0 0 1 2.5 2.5v7a2.5 2.5 0 0 1-2.5 2.5H15l-6 5v-5H4A2.5 2.5 0 0 1 1.5 11V4A2.5 2.5 0 0 1 4 1.5z" fill="none" stroke="currentColor" stroke-width="1.5" /></svg>
      <button class="tv-webcore-message-close" type="button" aria-label="Dismiss"></button>
    </div>
    <section class="tv-webcore-window">
      <header class="tv-webcore-window-bar">
        <h3 class="tv-webcore-window-title">welcome.txt</h3>
        <span class="tv-webcore-window-controls" aria-hidden="true">
          <span class="tv-webcore-window-min"></span>
          <span class="tv-webcore-window-max"></span>
          <span class="tv-webcore-window-close"></span>
        </span>
      </header>
      <div class="tv-webcore-window-body" tabindex="0">
        <p>Welcome to my little corner of the web. Sign the guestbook, take a picture from the folder, and stay a while.</p>
        <p>This site is best viewed at 800 × 600 with the volume up.</p>
      </div>
    </section>
    <div class="tv-webcore-progress" style="--tv-webcore-progress-value: 72%">
      <div class="tv-webcore-progress-bar">
        <span class="tv-webcore-progress-label">installing cuteness.exe</span>
        <span class="tv-webcore-progress-close" aria-hidden="true"></span>
      </div>
      <div class="tv-webcore-progress-track" role="progressbar" aria-label="Installing cuteness.exe" aria-valuemin="0" aria-valuemax="100" aria-valuenow="72">
        <span class="tv-webcore-progress-fill"></span>
      </div>
      <p class="tv-webcore-progress-note">72% · almost there</p>
    </div>
  </div>
  <div class="tv-webcore-scene-column">
    <section class="tv-webcore-captcha">
      <header class="tv-webcore-captcha-bar">
        <h3 class="tv-webcore-captcha-title">(1) captcha</h3>
        <span class="tv-webcore-captcha-close" aria-hidden="true"></span>
      </header>
      <div class="tv-webcore-captcha-body">
        <label class="tv-webcore-captcha-check">
          <input class="tv-webcore-captcha-box" type="checkbox" checked>
          <span>I'm not a robot</span>
        </label>
        <div class="tv-webcore-captcha-actions">
          <input class="tv-webcore-captcha-code" type="text" value="00110001" aria-label="Type the code" size="8">
          <button class="tv-webcore-captcha-button" type="button">yes</button>
          <button class="tv-webcore-captcha-button" type="button">no</button>
        </div>
      </div>
    </section>
    <section class="tv-webcore-dialog tv-webcore-dialog--violet">
      <header class="tv-webcore-dialog-bar">
        <h3 class="tv-webcore-dialog-title">system error</h3>
        <span class="tv-webcore-dialog-close" aria-hidden="true"></span>
      </header>
      <div class="tv-webcore-dialog-body">
        <p class="tv-webcore-dialog-message">The cat sat on the keyboard.</p>
        <div class="tv-webcore-dialog-actions">
          <button class="tv-webcore-dialog-button" type="button">ok</button>
          <button class="tv-webcore-dialog-button" type="button">oh, no</button>
        </div>
      </div>
    </section>
    <div class="tv-webcore-scene-buttons">
      <button class="tv-webcore-button tv-webcore-button--default" type="button">enter site</button>
      <button class="tv-webcore-button tv-webcore-button--lilac" type="button">guestbook</button>
    </div>
  </div>
</div>
```

```css
/* A pastel desktop: icons and a busy cursor down the side, windows and dialogs in two columns. Stacks when its container is narrow. */
.tv-webcore-scene {
  display: grid;
  grid-template-columns: minmax(0, 9rem) minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
  padding: 24px;
  background-color: color-mix(in srgb, var(--tv-webcore-lilac, #a49bf3) 26%, var(--tv-webcore-paper, #ffffff));
  background-image: radial-gradient(color-mix(in srgb, var(--tv-webcore-lilac, #a49bf3) 50%, transparent) 1px, transparent 1.3px);
  background-size: 8px 8px;
}

.tv-webcore-scene-column {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 22px;
  min-width: 0;
}

.tv-webcore-scene-column > * {
  max-width: none;
  margin: 0;
}

/* The icons sit straight on the desktop, in one column. */
.tv-webcore-scene .tv-webcore-icons {
  grid-template-columns: minmax(0, 1fr);
  padding: 0;
  background: none;
}

.tv-webcore-scene-side .tv-webcore-hourglass {
  justify-self: center;
}

.tv-webcore-scene-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

@container (max-width: 760px) {
  .tv-webcore-scene {
    grid-template-columns: minmax(0, 1fr);
    padding: 16px;
  }

  .tv-webcore-scene .tv-webcore-icons {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
```
