Full Code of jdan/98.css for AI

main b1d7a907371b cached
18 files
76.9 KB
21.0k tokens
3 symbols
1 requests
Download .txt
Repository: jdan/98.css
Branch: main
Commit: b1d7a907371b
Files: 18
Total size: 76.9 KB

Directory structure:
gitextract_f_8nzxj9/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── npm-publish.yml
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── build.js
├── docs/
│   ├── docs.css
│   ├── index.html.ejs
│   └── vs.css
├── fonts/
│   └── src/
│       ├── ms-sans-serif/
│       │   ├── license.txt
│       │   └── readme.txt
│       └── ms-sans-serif-bold/
│           ├── license.txt
│           └── readme.txt
├── now.json
├── package.json
├── server.js
└── style.css

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# https://editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 80
trim_trailing_whitespace = true

[*.md]
max_line_length = 0
trim_trailing_whitespace = false

[COMMIT_EDITMSG]
max_line_length = 0


================================================
FILE: .github/workflows/npm-publish.yml
================================================
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages

name: Publish to NPM

on:
  workflow_dispatch:
  release:
    types: [published]

jobs:
  publish-npm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16
          registry-url: https://registry.npmjs.org/
      - run: npm ci
      - run: npm run release
        env:
          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}


================================================
FILE: .gitignore
================================================
node_modules/
dist/


================================================
FILE: .npmignore
================================================
node_modules/


================================================
FILE: LICENSE
================================================
Copyright 2020 Jordan Scales

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
## 98.css

<a href="https://npm.im/98.css"><img height="29" alt="npm" src="https://98badges.now.sh/api/version" /></a>
<a href="https://unpkg.com/98.css"><img height="29" alt="gzip size" src="https://98badges.now.sh/api/size" /></a>

A design system for building faithful recreations of old UIs.

<img alt="a screenshot of a window with the title 'My First VB4 Program' and two buttons OK and Cancel, styled like a Windows 98 dialog" src="https://github.com/jdan/98.css/blob/main/docs/window.png?raw=true" height="133"> <img alt="a magnified view showing pixel-perfect borders on a scrollbar and button element" src="https://github.com/jdan/98.css/blob/main/docs/zoom.png?raw=true?raw=true" height="133">

98.css is a CSS file that takes semantic HTML and makes it look pretty. It does not ship with any JavaScript, so it is compatible with your frontend framework of choice.

Be sure to check out [XP.css](https://botoxparty.github.io/XP.css/) and [7.css](https://khang-nd.github.io/7.css/) as well.

### Installation / Usage

The easiest way to use 98.css is to import it from [unpkg](https://unpkg.com/).

```html
<!DOCTYPE html>
<html>
<head>
  <title>98.css example</title>
  <meta charset="UTF-8" />
  <link rel="stylesheet" href="https://unpkg.com/98.css" />
</head>

<body>
  <div class="window" style="margin: 32px; width: 250px">
    <div class="title-bar">
      <div class="title-bar-text">
        My First VB4 Program
      </div>
    </div>
    <div class="window-body">
      <p>Hello, world!</p>
    </div>
  </div>
</body>
</html>
```

Alternatively, you can grab 98.css for [the releases page](https://github.com/jdan/98.css/releases) or [npm](https://www.npmjs.com/package/98.css).

```
npm install 98.css
```

Here is an example of [98.css being used with React](https://codesandbox.io/s/objective-chandrasekhar-t5t6h?file=/src/index.js), and [an example with vanilla JavaScript](https://codesandbox.io/s/late-sound-miqho?file=/index.html).

Refer to the [documentation page](https://jdan.github.io/98.css/) for specific instructions on this library's components.

### Developing

First, run `npm install`.

[`style.css`](https://github.com/jdan/98.css/blob/main/style.css) is where everything happens.

You can use `npm start` to start a development environment that will watch for file changes and rebuild 98.css, reloading your browser in the process.

You can run a build manually with `npm run build`. This will write to the `dist/` directory.

### Issues, Contributing, etc.

Refer to [the GitHub issues page](https://github.com/jdan/98.css/issues) to see bugs in my CSS or report new ones. I'd really like to see your pull requests (especially those new to open-source!) and will happily provide code review. 98.css is a fun, silly project and I'd like to make it a fun place to build your open-source muscle.

Thank you for checking my little project out, I hope it brought you some joy today. Consider [starring/following along on GitHub](https://github.com/jdan/98.css/stargazers) and maybe reading my posts on [Bluesky](https://bsky.app/profile/jdan.me). 👋

### Publishing

Building the docs site: `npm run deploy:docs`

Publishing to npm: `npm run release`

### License

[MIT](https://github.com/jdan/98.css/blob/main/LICENSE)


================================================
FILE: build.js
================================================
#!/usr/bin/env node
const dedent = require("dedent");
const ejs = require("ejs");
const fs = require("fs");
const glob = require("glob");
const hljs = require("highlight.js");
const mkdirp = require("mkdirp");
const path = require("path");
const postcss = require("postcss");

const { homepage, version } = require("./package.json");

function buildCSS() {
  const input =
    `/*! 98.css v${version} - ${homepage} */\n` + fs.readFileSync("style.css");

  return postcss()
    .use(require("postcss-inline-svg"))
    .use(require("postcss-css-variables"))
    .use(require("postcss-calc"))
    .use(require("postcss-copy")({ dest: "dist", template: "[name].[ext]" }))
    .use(require("cssnano"))
    .process(input, {
      from: "style.css",
      to: "dist/98.css",
      map: { inline: false },
    })
    .then((result) => {
      mkdirp.sync("dist");
      fs.writeFileSync("dist/98.css", result.css);
      fs.writeFileSync("dist/98.css.map", result.map.toString());
    });
}

function buildDocs() {
  let id = 0;
  function getNewId() {
    return ++id;
  }
  function getCurrentId() {
    return id;
  }

  const template = fs.readFileSync("docs/index.html.ejs", "utf-8");
  function example(code) {
    const magicBrackets = /\[\[(.*)\]\]/g;
    const dedented = dedent(code);
    const inline = dedented.replace(magicBrackets, "$1");
    const escaped = hljs.highlight("html", dedented.replace(magicBrackets, ""))
      .value;

    return `<div class="example">
      ${inline}
      <details>
        <summary>Show code</summary>
        <pre><code>${escaped}</code></pre>
      </details>
    </div>`;
  }

  glob("docs/*", (err, files) => {
    if (!err) {
      files.forEach((srcFile) =>
        fs.copyFileSync(srcFile, path.join("dist", path.basename(srcFile)))
      );
    } else throw "error globbing dist directory.";
  });
  fs.writeFileSync(
    path.join(__dirname, "/dist/index.html"),
    ejs.render(template, { getNewId, getCurrentId, example })
  );
}

function build() {
  buildCSS()
    .then(buildDocs)
    .catch((err) => console.log(err));
}
module.exports = build;

build();


================================================
FILE: docs/docs.css
================================================
body {
  margin: 0;
  padding: 0;
  background: #c0c0c0;
}

main {
  width: 65rem;
  margin-left: 240px;
  margin-bottom: 60px;
}

aside {
  width: 200px;
  position: fixed;
  top: 0;
  bottom: 0;
  padding: 8px;
  display: flex;
  align-items: stretch;
}

aside .tree-view {
  width: 100%;
  /* TODO: Move scrollbar into the recessed region? */
  overflow-y: scroll;
}

h1 {
  margin: 12px 0;
}

hr {
  margin: 0;
  border: none;
  width: 400px;
  height: 1px;
  opacity: 0.5;
  background: linear-gradient(
    to right,
    red 20%,
    yellow 20%,
    yellow 36%,
    green 36%,
    green 60%,
    blue 60%,
    blue 100%
  );
}

h2 {
  margin-bottom: 12px;
}

h3 {
  font-size: 1.6rem;
}

h3,
h4 {
  /* Swap the margin for a top-padding so linking to this section
     results in a better scroll position */
  padding-top: 20px;
  margin-top: 0;
  display: block;
  flex: 0 0 180px;
}

p {
  max-width: 50rem;
  line-height: 1.5;
}

.component {
  display: flex;
  margin-top: 24px;
}

blockquote {
  margin: 0 0 20px;
  padding: 20px;
  background: #dfdfdf;
}

blockquote footer {
  margin: 12px 0 0 12px;
}

.example {
  margin: 16px 0;
  padding: 12px 24px;
  border-left: 1px solid #808080;
}

details {
  margin-top: 12px;
}

summary {
  user-select: none;
  cursor: pointer;
  display: inline;
}

details[open] summary {
  margin-bottom: 8px;
}

button.focused {
  outline: 1px dotted #000000;
  outline-offset: -4px;
}

button.active {
  box-shadow: inset -1px -1px #ffffff, inset 1px 1px #0a0a0a,
    inset -2px -2px #dfdfdf, inset 2px 2px #808080;
}

@media (max-width: 480px) {
  aside {
    display: none;
  }

  main {
    box-sizing: border-box;
    width: 100%;
    margin: 0;
    padding: 16px;
  }

  hr {
    width: 100%;
  }

  p {
    width: 100%;
  }

  h3,
  h4 {
    flex: 0;
  }

  .component {
    display: block;
    margin-top: 24px;
  }

  pre {
    overflow-x: scroll;
  }
}


================================================
FILE: docs/index.html.ejs
================================================
<!doctype html>
<html>
<head>
  <title>98.css - A design system for building faithful recreations of old UIs</title>
  <link rel="Shortcut Icon" type="image/x-icon" href="icon.png" />
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <meta property="og:title" content="98.css" />
  <meta name="Description" content="A design system for building faithful recreations of old UIs." />
  <meta property="og:description" content="A design system for building faithful recreations of old UIs." />
  <meta
    property="og:image"
    content="https://github.com/jdan/98.css/raw/main/docs/window.png?raw=true"
  />

  <link rel="stylesheet" href="98.css">
  <link rel="stylesheet" href="docs.css">
  <link rel="stylesheet" href="vs.css">
</head>
<body ontouchstart>
  <aside>
    <ul class="tree-view">
      <li><a href="#intro">Intro</a></li>
      <li>
        <a href="#components">Components</a>
        <ul>
          <li><a href="#button">Button</a></li>
          <li><a href="#checkbox">Checkbox</a></li>
          <li><a href="#option-button">OptionButton</a></li>
          <li><a href="#group-box">GroupBox</a></li>
          <li><a href="#text-box">TextBox</a></li>
          <li><a href="#slider">Slider</a></li>
          <li><a href="#dropdown">Dropdown</a></li>
          <li>
            <a href="#window">Window</a>
            <ul>
              <li><a href="#title-bar">Title Bar</a></li>
              <li><a href="#window-contents">Window contents</a></li>
              <li><a href="#status-bar">Status Bar</a></li>
            </ul>
          </li>
          <li><a href="#tree-view">TreeView</a></li>
          <li><a href="#tabs">Tabs</a></li>
          <li><a href="#table-view">TableView</a></li>
          <li><a href="#progress-indicator">Progress Indicator</a></li>
          <li><a href="#field-borders">Field borders</a></li>
        </ul>
      </li>
      <li><a href="#issues-contributing-etc">Issues, Contributing, etc.</a></li>
    </ul>
  </aside>

  <main>
    <h1>98.css</h1>
    <hr>
    <p>A design system for building faithful recreations of old UIs.</p>

    <p>
      <a href="http://npm.im/98.css" rel="nofollow" style="text-decoration: none">
        <img height="29" alt="npm" src="https://98badges.now.sh/api/version" style="max-width:100%;">
      </a>
      <a href="https://unpkg.com/98.css" rel="nofollow" style="text-decoration: none">
        <img height="29" alt="gzip size" src="https://98badges.now.sh/api/size" style="max-width:100%;">
      </a>
    </p>

    <h2 id="intro">Intro</h2>
    <p>
      98.css is a CSS library for building interfaces that look like Windows 98.
      See more <a href="https://github.com/jdan/98.css">on GitHub</a>.
    </p>

    <div class="window" style="margin: 32px; width: 250px">
      <div class="title-bar">
        <div class="title-bar-text">
          My First VB4 Program
        </div>

        <div class="title-bar-controls">
          <button aria-label="Minimize"></button>
          <button aria-label="Maximize"></button>
          <button aria-label="Close"></button>
        </div>
      </div>
      <div class="window-body">
        <p>Hello, world!</p>
        <section class="field-row" style="justify-content: flex-end">
          <button>OK</button>
          <button>Cancel</button>
        </section>
      </div>
    </div>

    <p>
      This library relies on the usage of <strong>semantic HTML</strong>. To make a button, you'll need
      to use a <code>&lt;button&gt;</code>. Input elements require labels. Icon buttons rely on
      <code>aria-label</code>. This page will guide you through that process, but accessibility is a primary
      goal of this project.
    </p>

    <p>
      You can override many of the styles of your elements while maintaining the appearance provided by
      this library. Need more padding on your buttons? Go for it. Need to add some color to your input labels?
      Be our guest.
    </p>

    <p>
      <strong>This library does not contain any JavaScript</strong>, it merely styles your HTML with some CSS.
      This means 98.css is compatible with your frontend framework of choice.
    </p>

    <p>
      Here is an example of <a href="https://codesandbox.io/s/objective-chandrasekhar-t5t6h?file=/src/index.js">98.css used with React</a>, and
      <a href="https://codesandbox.io/s/late-sound-miqho?file=/index.html">an example with vanilla JavaScript</a>. The fastest way to use 98.css is to import it from unpkg.
    </p>

    <pre style="max-width: 375px"><code>&lt;link
  rel="stylesheet"
  href="https://unpkg.com/98.css"
&gt;</code></pre>

    <p>
      You can install 98.css from the <a href="https://github.com/jdan/98.css/releases">GitHub releases page</a>, or <a href="https://www.npmjs.com/package/98.css">from npm</a>.
    </p>
    <pre style="max-width: 375px"><code>npm install 98.css</code></pre>

    <h2 id="components">Components</h2>

    <section class="component">
      <h3 id="button">Button</h3>
      <div>
        <blockquote>
          A <em>command button</em>, also referred to as a push button, is a control
          that causes the application to perform some action when the user clicks it.

          <footer>&mdash; Microsoft Windows User Experience p. 160</footer>
        </blockquote>

        <p>
          A standard button measures 75px wide and 23px tall, with a raised outer and inner border.
          They are given 12px of horizontal padding by default.
        </p>

        <%- example(`<button>Click me</button>
        <input type="submit" />
        <input type="reset" /> `)%>

        <p>
          You can add the class <code>default</code> to any button to apply additional styling,
          useful when communicating to the user what default action would happen in the active window if
          the <kbd>Enter</kbd> key was pressed on Windows 98.
        </p>

        <%- example(`<button class="default">OK</button>`)%>

        <p>
          When buttons are clicked, the raised borders become sunken.
          The following button is simulated to be in the pressed (active) state.
        </p>

        <% /* [[ ... ]] is used to render contents that
              will not appear in the "Show code" section */
        %>
        <%- example(`<button[[ class="active"]]>I am being pressed</button>`) %>

        <p>
          Disabled buttons maintain the same raised border, but have a "washed out"
          appearance in their label.
        </p>

        <%- example(`<button disabled>I cannot be clicked</button>`) %>

        <p>
          Button focus is communicated with a dotted border, set 4px within the contents of the button.
          The following example is simulated to be focused.
        </p>

        <%- example(`<button[[ class="focused"]]>I am focused</button>`) %>
      </div>
    </section>

    <section class="component">
      <h3 id="checkbox">Checkbox</h3>
      <div>
        <blockquote>
          A <em>check box</em> represents an independent or non-exclusive choice.
          <footer>&mdash; Microsoft Windows User Experience p. 167</footer>
        </blockquote>

        <p>
          Checkboxes are represented with a sunken panel, populated with a "check" icon when
          selected, next to a label indicating the choice.
        </p>

        <p>
          Note: You <strong>must</strong> include a corresponding label <strong>after</strong>
          your checkbox, using the <code>&lt;label&gt;</code> element with a <code>for</code> attribute
          pointed at the <code>id</code> of your input. This ensures the checkbox is easy to use with
          assistive technologies, on top of ensuring a good user experience for all (navigating with the tab key,
          being able to click the entire label to select the box).
        </p>

        <%- example(`
          <input type="checkbox" id="example${getNewId()}">
          <label for="example${getCurrentId()}">This is a checkbox</label>
        `) %>

        <p>
          Checkboxes can be selected and disabled with the standard <code>checked</code> and <code>disabled</code>
          attributes.
        </p>

        <p>
          When grouping inputs, wrap each input in a container with the <code>field-row</code> class. This ensures
          a consistent spacing between inputs.
        </p>

        <%- example(`
          <div class="field-row">
            <input checked type="checkbox" id="example${getNewId()}">
            <label for="example${getCurrentId()}">I am checked</label>
          </div>
          <div class="field-row">
            <input disabled type="checkbox" id="example${getNewId()}">
            <label for="example${getCurrentId()}">I am inactive</label>
          </div>
          <div class="field-row">
            <input checked disabled type="checkbox" id="example${getNewId()}">
            <label for="example${getCurrentId()}">I am inactive but still checked</label>
          </div>
        `) %>
      </div>
    </section>

    <section class="component">
      <h3 id="option-button">OptionButton</h3>
      <div>
        <blockquote>
          An <em>option button</em>, also referred to as a radio button, represents a single
          choice within a limited set of mutually exclusive choices. That is, the user can choose only
          one set of options.

          <footer>&mdash; Microsoft Windows User Experience p. 164</footer>
        </blockquote>

        <p>
          Option buttons can be used via the <code>radio</code> type on an input element.
        </p>

        <p>
          Option buttons can be grouped by specifying a shared <code>name</code> attribute on each
          input. Just as before: when grouping inputs, wrap each input in a container with the
          <code>field-row</code> class to ensure a consistent spacing between inputs.
        </p>

        <%- example(`
          <div class="field-row">
            <input id="radio${getNewId()}" type="radio" name="first-example">
            <label for="radio${getCurrentId()}">Yes</label>
          </div>
          <div class="field-row">
            <input id="radio${getNewId()}" type="radio" name="first-example">
            <label for="radio${getCurrentId()}">No</label>
          </div>
        `) %>

        <p>
          Option buttons can also be <code>checked</code> and <code>disabled</code> with their corresponding
          HTML attributes.
        </p>

        <%- example(`
          <div class="field-row">
            <input id="radio${getNewId()}" type="radio" name="second-example">
            <label for="radio${getCurrentId()}">Peanut butter should be smooth</label>
          </div>
          <div class="field-row">
            <input checked disabled id="radio${getNewId()}" type="radio" name="second-example">
            <label for="radio${getCurrentId()}">I understand why people like crunchy peanut butter</label>
          </div>
          <div class="field-row">
            <input disabled id="radio${getNewId()}" type="radio" name="second-example">
            <label for="radio${getCurrentId()}">Crunchy peanut butter is good</label>
          </div>
        `) %>
      </div>
    </section>

    <section class="component">
      <h3 id="group-box">GroupBox</h3>
      <div>
        <blockquote>
          A <em>group box</em> is a special control you can use to organize a set of
          controls. A group box is a rectangular frame with an optional label that surrounds
          a set of controls.

          <footer>&mdash; Microsoft Windows User Experience p. 189</footer>
        </blockquote>

        <p>
          A group box can be used by wrapping your elements with the <code>fieldset</code> tag.
          It contains a sunken outer border and a raised inner border, resembling an engraved box
          around your controls.
        </p>

        <%- example(`
          <fieldset>
            <div class="field-row">Select one:</div>
            <div class="field-row">
              <input id="radio${getNewId()}" type="radio" name="fieldset-example">
              <label for="radio${getCurrentId()}">Diners</label>
            </div>
            <div class="field-row">
              <input id="radio${getNewId()}" type="radio" name="fieldset-example">
              <label for="radio${getCurrentId()}">Drive-Ins</label>
            </div>
            <div class="field-row">
              <input id="radio${getNewId()}" type="radio" name="fieldset-example">
              <label for="radio${getCurrentId()}">Dives</label>
            </div>
          </fieldset>
        `) %>

        <p>
          You can provide your group with a label by placing a <code>legend</code> element
          within the <code>fieldset</code>.
        </p>

        <%- example(`
          <fieldset>
            <legend>Today's mood</legend>
            <div class="field-row">
              <input id="radio${getNewId()}" type="radio" name="fieldset-example2">
              <label for="radio${getCurrentId()}">Claire Saffitz</label>
            </div>
            <div class="field-row">
              <input id="radio${getNewId()}" type="radio" name="fieldset-example2">
              <label for="radio${getCurrentId()}">Brad Leone</label>
            </div>
            <div class="field-row">
              <input id="radio${getNewId()}" type="radio" name="fieldset-example2">
              <label for="radio${getCurrentId()}">Chris Morocco</label>
            </div>
            <div class="field-row">
              <input id="radio${getNewId()}" type="radio" name="fieldset-example2">
              <label for="radio${getCurrentId()}">Carla Lalli Music</label>
            </div>
          </fieldset>
        `) %>
      </div>
    </section>

    <section class="component">
      <h3 id="text-box">TextBox</h3>
      <div>
        <blockquote>
          A <em>text box</em> (also referred to as an edit control) is a
          rectangular control where the user enters or edits text. It can
          be defined to support a single line or multiple lines of text.

          <footer>&mdash; Microsoft Windows User Experience p. 181</footer>
        </blockquote>

        <p>
          Text boxes can rendered by specifying a <code>text</code> type on an
          <code>input</code> element. As with checkboxes and radio buttons, you
          should provide a corresponding label with a properly set <code>for</code>
          attribute, and wrap both in a container with the <code>field-row</code> class.
        </p>

        <%- example(`
          <div class="field-row">
            <label for="text${getNewId()}">Occupation</label>
            <input id="text${getCurrentId()}" type="text" />
          </div>
        `) %>

        <p>
          Additionally, you can make use of the <code>field-row-stacked</code> class
          to position your label above the input instead of beside it.
        </p>

        <%- example(`
          <div class="field-row-stacked" style="width: 200px">
            <label for="text${getNewId()}">Address (Line 1)</label>
            <input id="text${getCurrentId()}" type="text" />
          </div>
          <div class="field-row-stacked" style="width: 200px">
            <label for="text${getNewId()}">Address (Line 2)</label>
            <input id="text${getCurrentId()}" type="text" />
          </div>
        `) %>

        <p>
          To support multiple lines in the user's input, use the <code>textarea</code>
          element instead.
        </p>

        <%- example(`
          <div class="field-row-stacked" style="width: 200px">
            <label for="text${getNewId()}">Additional notes</label>
            <textarea id="text${getCurrentId()}" rows="8"></textarea>
          </div>
        `) %>

        <p>
          Text boxes can also be disabled and have value with their corresponding HTML attributes.
        </p>

        <%- example(`
          <div class="field-row">
            <label for="text${getNewId()}">Favorite color</label>
            <input id="text${getCurrentId()}" disabled type="text" value="Windows Green"/>
          </div>
        `) %>
      </div>


    </section>

    <section class="component">
      <h3 id="slider">Slider</h3>
      <div>
        <blockquote>
          A <em>slider</em>, sometimes called a trackbar control, consists of a bar that
          defines the extent or range of the adjustment and an indicator that
          shows the current value for the control...

          <footer>&mdash; Microsoft Windows User Experience p. 146</footer>
        </blockquote>

        <p>
          Sliders can rendered by specifying a <code>range</code> type on an
          <code>input</code> element.
        </p>

        <%- example(`
          <div class="field-row" style="width: 300px">
            <label for="range${getNewId()}">Volume:</label>
            <label for="range${getNewId()}">Low</label>
            <input id="range${getCurrentId()}" type="range" min="1" max="11" value="5" />
            <label for="range${getNewId()}">High</label>
          </div>
        `) %>

        <p>
          You can make use of the <code>has-box-indicator</code> class replace the
          default indicator with a box indicator, furthermore the slider can be wrapped
          with a <code>div</code> using <code>is-vertical</code> to display the input vertically.
        </p>

        <p>
          Note: To change the length of a vertical slider, the <code>input</code> width
          and <code>div</code> height.
        </p>

        <%- example(`
          <div class="field-row">
            <label for="range${getNewId()}">Cowbell</label>
            <div class="is-vertical">
              <input id="range${getCurrentId()}" class="has-box-indicator" type="range" min="1" max="3" step="1" value="2" />
            </div>
          </div>
        `) %>
      </div>
    </section>

    <section class="component">
      <h3 id="dropdown">Dropdown</h3>
      <div>
        <blockquote>
          A <em>drop-down list box</em> allows the selection of only a
          single item from a list. In its closed state, the control displays
          the current value for the control. The user opens the list to change
          the value.

          <footer>
            &mdash; Microsoft Windows User Experience p. 175
          </footer>
        </blockquote>

        <p>
          Dropdowns can be rendered by using the <code>select</code> and <code>option</code>
          elements.
        </p>

        <%- example(`
          <select>
            <option>5 - Incredible!</option>
            <option>4 - Great!</option>
            <option>3 - Pretty good</option>
            <option>2 - Not so great</option>
            <option>1 - Unfortunate</option>
          </select>
        `) %>

        <p>
          By default, the first option will be selected. You can change this by
          giving one of your <code>option</code> elements the <code>selected</code>
          attribute.
        </p>

        <%- example(`
          <select>
            <option>5 - Incredible!</option>
            <option>4 - Great!</option>
            <option selected>3 - Pretty good</option>
            <option>2 - Not so great</option>
            <option>1 - Unfortunate</option>
          </select>
        `) %>
      </div>
    </section>

    <h3 id="window">Window</h3>
    <p>
      The following components illustrate how to build complete windows using
      98.css.
    </p>

    <section class="component">
      <h4 id="title-bar">Title Bar</h4>
      <div>
        <blockquote>
          At the top edge of the window, inside its border, is the title bar
          (also reffered to as the caption or caption bar), which extends across
          the width of the window. The title bar identifies the contents of the
          window.

          <footer>
            &mdash; Microsoft Windows User Experience p. 118
          </footer>
        </blockquote>

        <blockquote>
          Include command buttons associated with the common commands of the
          primary window in the title bar. These buttons act as shortcuts to specific
          window commands.

          <footer>
            &mdash; Microsoft Windows User Experience p. 122
          </footer>
        </blockquote>

        <p>
          You can build a complete title bar by making use of three classes,
          <code>title-bar</code>, <code>title-bar-text</code>, and <code>title-bar-controls</code>.
        </p>

        <%- example(`
          <div class="title-bar">
            <div class="title-bar-text">A Title Bar</div>
            <div class="title-bar-controls">
              <button aria-label="Close"></button>
            </div>
          </div>
        `) %>

        <p>
          We make use of <code>aria-label</code> to render the Close button, to let
          assistive technologies know the intent of this button. You may also use
          "Minimize", "Maximize", "Restore" and "Help" like so:
        </p>

        <%- example(`
          <div class="title-bar">
            <div class="title-bar-text">A Title Bar</div>
            <div class="title-bar-controls">
              <button aria-label="Minimize"></button>
              <button aria-label="Maximize"></button>
              <button aria-label="Close"></button>
            </div>
          </div>

          <br />

          <div class="title-bar">
            <div class="title-bar-text">A Maximized Title Bar</div>
            <div class="title-bar-controls">
              <button aria-label="Minimize"></button>
              <button aria-label="Restore"></button>
              <button aria-label="Close"></button>
            </div>
          </div>

          <br />

          <div class="title-bar">
            <div class="title-bar-text">A Helpful Bar</div>
            <div class="title-bar-controls">
              <button aria-label="Help"></button>
              <button aria-label="Close"></button>
            </div>
          </div>
        `) %>

        <p>
          Each <code>aria-label</code> also has a corresponding styling class to render the title bar buttons,
          to let the <code>aria-label</code> text be in other languages without causing rendering, accessibility, or localization issues.
        </p>

        <%- example(`
          <div class="title-bar">
            <div class="title-bar-text">A Title Bar using Button Styling Classes</div>
            <div class="title-bar-controls">
              <button aria-label="Any Text" class="minimize"></button>
              <button aria-label="Any Text" class="maximize"></button>
              <button aria-label="Any Text" class="close"></button>
            </div>
          </div>

          <br />

          <div class="title-bar">
            <div class="title-bar-text">A Maximized Title Bar using Button Styling Classes</div>
            <div class="title-bar-controls">
              <button aria-label="Any Text" class="minimize"></button>
              <button aria-label="Any Text" class="restore"></button>
              <button aria-label="Any Text" class="close"></button>
            </div>
          </div>

          <br />

          <div class="title-bar">
            <div class="title-bar-text">A Helpful Bar using Button Styling Classes</div>
            <div class="title-bar-controls">
              <button aria-label="Any Text" class="help"></button>
              <button aria-label="Any Text" class="close"></button>
            </div>
          </div>
        `) %>

    <p>
        Maximize buttons can be disabled, useful when making a window appear as if it cannot be maximized.
    </p>

    <%- example(`
          <div class="title-bar">
            <div class="title-bar-text">A Title Bar with Maximize disabled</div>
            <div class="title-bar-controls">
              <button aria-label="Minimize"></button>
              <button aria-label="Maximize" disabled></button>
              <button aria-label="Close"></button>
            </div>
          </div>
      `) %>

		<p>
          You can make a title bar "inactive" by adding <code>inactive</code> class,
		  useful when making more than one window.
        </p>
		 <%- example(`
          <div class="title-bar inactive">
            <div class="title-bar-text">An inactive title bar</div>
            <div class="title-bar-controls">
              <button aria-label="Close"></button>
            </div>
          </div>
        `) %>
      </div>
    </section>

    <section class="component">
      <h4 id="window-contents">Window contents</h4>
      <div>
        <blockquote>
          Every window has a boundary that defines its shape.

          <footer>
            &mdash; Microsoft Windows User Experience p. 118
          </footer>
        </blockquote>

        <p>
          To give our title bar a home, we make use of the <code>window</code>
          class. This provides a raised outer and inner border, as well as some
          padding. We can freely resize the window by specifying a width in the
          container style.
        </p>

        <%- example(`
          <div class="window" style="width: 300px">
            <div class="title-bar">
              <div class="title-bar-text">A Complete Window</div>
              <div class="title-bar-controls">
                <button aria-label="Minimize"></button>
                <button aria-label="Maximize"></button>
                <button aria-label="Close"></button>
              </div>
            </div>
          </div>
        `) %>

        <p>
          To draw the contents of the window, we use the <code>window-body</code>
          class under the title bar.
        </p>

        <%- example(`
          <div class="window" style="width: 300px">
            <div class="title-bar">
              <div class="title-bar-text">A Window With Stuff In It</div>
              <div class="title-bar-controls">
                <button aria-label="Minimize"></button>
                <button aria-label="Maximize"></button>
                <button aria-label="Close"></button>
              </div>
            </div>
            <div class="window-body">
              <p>There's so much room for activities!</p>
            </div>
          </div>
        `) %>
      </div>
    </section>

    <section class="component">
      <h4 id="status-bar">Status Bar</h4>
      <div>
        <blockquote>
          A status bar is a special area within a window, typically the bottom, that displays information
          about the current state of what is being viewed in the window or any other contextual information, such as keyboard
          state.

          <footer>
            &mdash; Microsoft Windows User Experience p. 146
          </footer>
        </blockquote>

        <p>
          You can render a status bar with the <code>status-bar</code> class,
          and <code>status-bar-field</code> for every child text element.
        </p>

        <%- example(`
        <div class="window" style="width: 320px">
          <div class="title-bar">
            <div class="title-bar-text">A Window With A Status Bar</div>
          </div>
          <div class="window-body">
        <p> There are just so many possibilities:</p>
        <ul>
            <li>A Task Manager</li>
            <li>A Notepad</li>
            <li>Or even a File Explorer!</li>
        </ul>
          </div>
          <div class="status-bar">
            <p class="status-bar-field">Press F1 for help</p>
            <p class="status-bar-field">Slide 1</p>
            <p class="status-bar-field">CPU Usage: 14%</p>
          </div>
        </div>
      `) %>


    </section>

    <section class="component">
      <h3 id="tree-view">TreeView</h3>
      <div>
        <blockquote>
          A <em>tree view control</em> is a special list box control
          that displays a set of objects as an indented outline based
          on their logical hierarchical relationship.

          <footer>
            &mdash; Microsoft Windows User Experience p. 178
          </footer>
        </blockquote>

        <p>
          To render a tree view, use an <code>ul</code> element with the
          <code>tree-view</code> class. The children of this list (<code>li</code>
          elements), can contain whatever you'd like.
        </p>

        <%- example(`
          <ul class="tree-view">
            <li>We can put</li>
            <li><strong style="color: purple">✨ Whatever ✨</strong></li>
            <li>We want in here</li>
          </ul>
        `) %>

        <p>
          To make this a tree, we can nest further <code>ul</code> elements
          (no class needed on these). This will provide them with a nice dotted
          border and indentation to illustrate the structure of the tree.
        </p>
        <p>
          To create expandable sections, wrap child lists inside of
          <code>details</code> elements.
        </p>

        <%- example(`
          <ul class="tree-view">
            <li>Table of Contents</li>
            <li>What is web development?</li>
            <li>
              CSS
              <ul>
                <li>Selectors</li>
                <li>Specificity</li>
                <li>Properties</li>
              </ul>
            </li>
            <li>
              <details open>
                <summary>JavaScript</summary>
                <ul>
                  <li>Avoid at all costs</li>
                  <li>
                    <details>
                      <summary>Unless</summary>
                      <ul>
                        <li>Avoid</li>
                        <li>
                          <details>
                            <summary>At</summary>
                            <ul>
                              <li>Avoid</li>
                              <li>At</li>
                              <li>All</li>
                              <li>Cost</li>
                            </ul>
                          </details>
                        </li>
                        <li>All</li>
                        <li>Cost</li>
                      </ul>
                    </details>
                  </li>
                </ul>
              </details>
            </li>
            <li>HTML</li>
            <li>Special Thanks</li>
          </ul>
        `) %>
      </div>
    </section>

    <section class="component">
      <h3 id="tabs">Tabs</h3>
      <div>
        <blockquote>
          A <em>tab control</em> is analogous to a divider in a file cabinet or notebook.
          You can use this control to define multiple logical pages or sections of information within the same window.

          <footer>
            &mdash; Microsoft Windows User Experience p. 193
          </footer>
        </blockquote>

        <p>
          To render a tab list, use a <code>menu</code> element with the
          <code>[role=tablist]</code> attribute. The children of this menu (<code>li</code>
          elements), should get a <code>[role=tab]</code> attribute.
        </p>

        <p>
          Tabs should be managed by adding custom javascript code.
          All you need is to add the <code>[aria-selected=true]</code> attribute to the active tab.
        </p>

        <%- example(`
        <div class="window-body">
          <p>Hello, world!</p>

          <menu role="tablist">
            <li role="tab" aria-selected="true"><a href="#tabs">Desktop</a></li>
            <li role="tab"><a href="#tabs">My computer</a></li>
            <li role="tab"><a href="#tabs">Control panel</a></li>
            <li role="tab"><a href="#tabs">Devices manager</a></li>
            <li role="tab"><a href="#tabs">Hardware profiles</a></li>
            <li role="tab"><a href="#tabs">Performance</a></li>
          </menu>
          <div class="window" role="tabpanel">
            <div class="window-body">
              <p>the tab content</p>
            </div>
          </div>
        </div>
        `) %>

        <p>
          To create multirows tabs, add a <code>multirows</code>
          class to the <code>menu</code> tag.
        </p>

        <%- example(`
        <div class="window-body">
          <p>Hello, world!</p>

          <menu role="tablist" class="multirows">
            <li role="tab"><a href="#tabs">Desktop</a></li>
            <li role="tab"><a href="#tabs">My computer</a></li>
            <li role="tab"><a href="#tabs">Control panel</a></li>
            <li role="tab"><a href="#tabs">Devices manager</a></li>
            <li role="tab"><a href="#tabs">Hardware profiles</a></li>
            <li role="tab"><a href="#tabs">Performance</a></li>
          </menu>
          <menu role="tablist" class="multirows">
            <li role="tab"><a href="#tabs">Users</a></li>
            <li role="tab"><a href="#tabs">Network</a></li>
            <li role="tab"><a href="#tabs">Programs</a></li>
            <li role="tab"><a href="#tabs">Services</a></li>
            <li role="tab"><a href="#tabs">Resources</a></li>
            <li role="tab"><a href="#tabs">Advanced</a></li>
          </menu>
          <div class="window" role="tabpanel">
            <div class="window-body">
              <p>the tab content</p>
            </div>
          </div>
        </div>
        `) %>
              </div>
    </section>
    <section class="component">
      <h3 id="table-view">TableView</h3>
      <div>
        <p>
          To render a table view, use a table element. Wrap it with a div element with <code>sunken-panel</code> class to provide proper border and overflow container.
        </p>
        <p>
          With a bit of extra scripting you can make table view interactive. Give <code>interactive</code> class to
          table element to show pointer cursor when hovering over body rows. Table rows can be given
          <code>highlighted</code> class to appear selected.
        </p>

        <%- example(`
          <div class="sunken-panel" style="height: 120px; width: 240px;">
            <table class="interactive">
              <thead>
                <tr>
                  <th>Name</th>
                  <th>Version</th>
                  <th>Company</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>MySQL ODBC 3.51 Driver</td>
                  <td>3.51.11.00</td>
                  <td>MySQL AB</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
                <tr>
                  <td>SQL Server</td>
                  <td>3.70.06.23</td>
                  <td>Microsoft Corporation</td>
                </tr>
              </tbody>
            </table>
          </div>
          <script>
            document.querySelectorAll('table.interactive').forEach(element => {
              element.addEventListener('click', (event) => {
                const highlightedClass = 'highlighted';
                const isRow = element => element.tagName === 'TR' && element.parentElement.tagName === 'TBODY';
                const newlySelectedRow = event.composedPath().find(isRow);
                const previouslySelectedRow = Array.from(newlySelectedRow.parentElement.children).filter(isRow).find(element => element.classList.contains(highlightedClass));
                if(previouslySelectedRow){
                  previouslySelectedRow.classList.toggle(highlightedClass);
                }

                if (newlySelectedRow) {
                  newlySelectedRow.classList.toggle(highlightedClass);
                }
              })
            });
          </script>
      `) %>
    </div>
    </section>

    <section class="component">
      <h3 id="progress-indicator">Progress Indicator</h3>
      <div>
        <blockquote>
          You can use a <em>progress indicator</em>, also known as a <em>progress bar control</em>, to show the percentage of completion of a lengthy operation.

          <footer>
            &mdash; Microsoft Windows User Experience p. 189
          </footer>
        </blockquote>

        <p>
          There are two types of progress bars: solid and segmented. The solid version is the default. To declare a segmented bar, you should use the <code>segmented</code> class.
        </p>

        <%- example(`
          <div class="progress-indicator">
            <span class="progress-indicator-bar"  style="width: 40%;" />
          </div>
        `) %>

        <%- example(`
          <div class="progress-indicator segmented">
            <span class="progress-indicator-bar" style="width: 40%;" />
          </div>
        `) %>
      </div>
    </section>

    <section class="component">
      <h3 id="field-borders">Field borders</a></li></h3>
      <div>
        <blockquote>
          Text boxes, check boxes, drop-down list boxes, spin boxes and list
          boxes use the <em>field border style</em>. You can also use the style
          for define the work area within a window. It uses the sunken outer and
          sunken inner basic border styles.

          For most controls, the interior of the field uses the button highlight
          color. For text fields, such as text boxes and combo boxes, the
          interior uses the button face color when the field is read-only or
          disabled.

          <footer>
            &mdash; Microsoft Windows User Experience p. 421
          </footer>
        </blockquote>

        <blockquote>
          Status fields use the <em>status field border style</em>. This style
          uses only the sunken outer basic border style. You use the status
          field style in status bars and other read-only fields where the
          content of the file can change dynamically.

          <footer>
            &mdash; Microsoft Windows User Experience p. 422
          </footer>
        </blockquote>

        As mentioned in these guidelines, these styles are used in other
        contexts than just form elements and status fields such as to indicate
        work areas and dynamic content. For that reason, we provide three
        classes for these generic usages, <code>field-border</code>,
        <code>field-border-disabled</code>, and
        <code>status-field-border</code>. These classes only define the border
        and background color and minimal padding, so you will typically need to
        at least provide some extra padding yourself.

        <%- example(`
          <div class="field-border" style="padding: 8px">
            Work area
          </div>
        `) %>


        <%- example(`
          <div class="field-border-disabled" style="padding: 8px">
            Disabled work area
          </div>
        `) %>

        <%- example(`
          <div class="status-field-border" style="padding: 8px">
            Dynamic content
          </div>
        `) %>
      </div>
    </section>

    <h2 id="issues-contributing-etc">Issues, Contributing, etc.</h2>

    <p>
      98.css is <a href="https://github.com/jdan/98.css/blob/main/LICENSE">MIT licensed</a>.
    </p>

    <p>
      Refer to <a href="https://github.com/jdan/98.css/issues">the GitHub issues page</a> to see bugs
      in my CSS or report new ones. I'd really like to see your pull requests (especially those new to
      open-source!) and will happily provide code review. 98.css is a fun, silly project and I'd like
      to make it a fun place to build your open-source muscle.
    </p>

    <p>
      Thank you for checking my little project out, I hope it brought you some joy today. Consider
      <a href="https://github.com/jdan/98.css/stargazers">starring/following along on GitHub</a> and maybe
      subscribing to more fun things on <a href="https://twitter.com/jdan">my twitter</a>. 👋
    </p>
  </main>
</body>
</html>


================================================
FILE: docs/vs.css
================================================
/*

Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>

*/
.hljs {
  display: block;
  overflow-x: auto;
  padding: 0.5em;
  background: white;
  color: black;
}

.hljs-comment,
.hljs-quote,
.hljs-variable {
  color: #008000;
}

.hljs-keyword,
.hljs-selector-tag,
.hljs-built_in,
.hljs-name,
.hljs-tag {
  color: #00f;
}

.hljs-string,
.hljs-title,
.hljs-section,
.hljs-attribute,
.hljs-literal,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-addition {
  color: #a31515;
}

.hljs-deletion,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-meta {
  color: #2b91af;
}

.hljs-doctag {
  color: #808080;
}

.hljs-attr {
  color: #f00;
}

.hljs-symbol,
.hljs-bullet,
.hljs-link {
  color: #00b0e8;
}

.hljs-emphasis {
  font-style: italic;
}

.hljs-strong {
  font-weight: bold;
}


================================================
FILE: fonts/src/ms-sans-serif/license.txt
================================================
The FontStruction “MS Sans Serif”
(https://fontstruct.com/fontstructions/show/1384746) by “lou” is licensed
under a Creative Commons Attribution Share Alike license
(http://creativecommons.org/licenses/by-sa/3.0/).


================================================
FILE: fonts/src/ms-sans-serif/readme.txt
================================================
The font file in this archive was created using Fontstruct the free, online
font-building tool.
This font was created by “lou”.
This font has a homepage where this archive and other versions may be found:
https://fontstruct.com/fontstructions/show/1384746

Try Fontstruct at http://fontstruct.com
It’s easy and it’s fun.

NOTE FOR FLASH USERS: Fontstruct fonts (fontstructions) are optimized for Flash.
If the font in this archive is a pixel font, it is best displayed at a font-size
of 11.

Fontstruct is sponsored by FontShop.
Visit them at https://fontshop.com
FontShop is the original independent font retailer. We’ve been around since
the dawn of digital type. Whether you need the right font or need to create the
right font from scratch, let our 26 years of experience work for you.

Fontstruct is copyright ©2017 Rob Meek

LEGAL NOTICE:
In using this font you must comply with the licensing terms described in the
file “license.txt” included with this archive.
If you redistribute the font file in this archive, it must be accompanied by all
the other files from this archive, including this one.


================================================
FILE: fonts/src/ms-sans-serif-bold/license.txt
================================================
The FontStruction “MS Sans Serif Bold”
(https://fontstruct.com/fontstructions/show/1384862) by “lou” is licensed
under a Creative Commons Attribution Share Alike license
(http://creativecommons.org/licenses/by-sa/3.0/).


================================================
FILE: fonts/src/ms-sans-serif-bold/readme.txt
================================================
The font file in this archive was created using Fontstruct the free, online
font-building tool.
This font was created by “lou”.
This font has a homepage where this archive and other versions may be found:
https://fontstruct.com/fontstructions/show/1384862

Try Fontstruct at http://fontstruct.com
It’s easy and it’s fun.

NOTE FOR FLASH USERS: Fontstruct fonts (fontstructions) are optimized for Flash.
If the font in this archive is a pixel font, it is best displayed at a font-size
of 11.

Fontstruct is sponsored by FontShop.
Visit them at https://fontshop.com
FontShop is the original independent font retailer. We’ve been around since
the dawn of digital type. Whether you need the right font or need to create the
right font from scratch, let our 26 years of experience work for you.

Fontstruct is copyright ©2017 Rob Meek

LEGAL NOTICE:
In using this font you must comply with the licensing terms described in the
file “license.txt” included with this archive.
If you redistribute the font file in this archive, it must be accompanied by all
the other files from this archive, including this one.


================================================
FILE: now.json
================================================
{
  "version": 2,
  "public": true
}


================================================
FILE: package.json
================================================
{
  "name": "98.css",
  "version": "0.1.21",
  "description": "A design system for building faithful recreations of old UIs",
  "main": "dist/98.css",
  "directories": {
    "doc": "docs"
  },
  "scripts": {
    "build": "node build.js",
    "deploy:docs": "npm run build && gh-pages -d dist",
    "release": "npm run build && npm publish"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/jdan/98.css.git"
  },
  "keywords": [
    "css",
    "windows98"
  ],
  "author": "Jordan Scales <scalesjordan@gmail.com>",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/jdan/98.css/issues"
  },
  "homepage": "https://github.com/jdan/98.css",
  "devDependencies": {
    "chokidar": "^3.3.1",
    "cssnano": "^5.0.1",
    "dedent": "^0.7.0",
    "ejs": "^3.0.2",
    "gh-pages": "^2.2.0",
    "glob": "^7.1.6",
    "highlight.js": "^10.4.1",
    "live-server": "^1.2.1",
    "mkdirp": "^1.0.4",
    "postcss": "^8.2.12",
    "postcss-calc": "^7.0.2",
    "postcss-copy": "^7.1.0",
    "postcss-css-variables": "^0.14.0",
    "postcss-inline": "^1.2.0",
    "postcss-inline-svg": "^4.1.0"
  }
}


================================================
FILE: server.js
================================================
const chokidar = require("chokidar");
const build = require("./build");

chokidar
  .watch(["style.css", "build.js", "docs", "fonts", "icon"], {
    usePolling: true,
  })
  .on("change", (file) => {
    console.log(
      `[${new Date().toLocaleTimeString()}] ${file} changed -- rebuilding...`
    );
    build();
  });

var liveServer = require("live-server");
liveServer.start({ port: 3000, root: "dist" });


================================================
FILE: style.css
================================================
/**
 * 98.css
 * Copyright (c) 2020 Jordan Scales <thatjdanisso.cool>
 * https://github.com/jdan/98.css/blob/main/LICENSE
 */

:root {
  /* Color */
  --text-color: #222222;
  --surface: #c0c0c0;
  --button-highlight: #ffffff;
  --button-face: #dfdfdf;
  --button-shadow: #808080;
  --window-frame: #0a0a0a;
  --dialog-blue: #000080;
  --dialog-blue-light: #1084d0;
  --dialog-gray: #808080;
  --dialog-gray-light: #b5b5b5;
  --link-blue: #0000ff;

  /* Spacing */
  --element-spacing: 8px;
  --grouped-button-spacing: 4px;
  --grouped-element-spacing: 6px;
  --radio-width: 12px;
  --checkbox-width: 13px;
  --radio-label-spacing: 6px;
  --range-track-height: 4px;
  --range-spacing: 10px;

  /* Some detailed computations for radio buttons and checkboxes */
  --radio-total-width-precalc: var(--radio-width) + var(--radio-label-spacing);
  --radio-total-width: calc(var(--radio-total-width-precalc));
  --radio-left: calc(-1 * var(--radio-total-width-precalc));
  --radio-dot-width: 4px;
  --radio-dot-top: calc(var(--radio-width) / 2 - var(--radio-dot-width) / 2);
  --radio-dot-left: calc(
    -1 * (var(--radio-total-width-precalc)) + var(--radio-width) / 2 - var(
        --radio-dot-width
      ) / 2
  );

  --checkbox-total-width-precalc: var(--checkbox-width) +
    var(--radio-label-spacing);
  --checkbox-total-width: calc(var(--checkbox-total-width-precalc));
  --checkbox-left: calc(-1 * var(--checkbox-total-width-precalc));
  --checkmark-width: 7px;
  --checkmark-left: 3px;

  /* Borders */
  --border-width: 1px;
  --border-raised-outer: inset -1px -1px var(--window-frame),
    inset 1px 1px var(--button-highlight);
  --border-raised-inner: inset -2px -2px var(--button-shadow),
    inset 2px 2px var(--button-face);
  --border-sunken-outer: inset -1px -1px var(--button-highlight),
    inset 1px 1px var(--window-frame);
  --border-sunken-inner: inset -2px -2px var(--button-face),
    inset 2px 2px var(--button-shadow);
  --default-button-border-raised-outer: inset -2px -2px var(--window-frame), inset 1px 1px var(--window-frame);
  --default-button-border-raised-inner: inset 2px 2px var(--button-highlight), inset -3px -3px var(--button-shadow), inset 3px 3px var(--button-face);
  --default-button-border-sunken-outer: inset 2px 2px var(--window-frame), inset -1px -1px var(--window-frame);
  --default-button-border-sunken-inner: inset -2px -2px var(--button-highlight), inset 3px 3px var(--button-shadow), inset -3px -3px var(--button-face);


  /* Window borders flip button-face and button-highlight */
  --border-window-outer: inset -1px -1px var(--window-frame),
    inset 1px 1px var(--button-face);
  --border-window-inner: inset -2px -2px var(--button-shadow),
    inset 2px 2px var(--button-highlight);

  /* Field borders (checkbox, input, etc) flip window-frame and button-shadow */
  --border-field: inset -1px -1px var(--button-highlight),
    inset 1px 1px var(--button-shadow), inset -2px -2px var(--button-face),
    inset 2px 2px var(--window-frame);
  --border-status-field: inset -1px -1px var(--button-face), inset 1px 1px var(--button-shadow);

  /* Tabs */
  --border-tab: inset -1px 0 var(--window-frame),
    inset 1px 1px var(--button-face),
    inset -2px 0 var(--button-shadow),
    inset 2px 2px var(--button-highlight)
}

@font-face {
  font-family: "Pixelated MS Sans Serif";
  src: url("fonts/converted/ms_sans_serif.woff") format("woff");
  src: url("fonts/converted/ms_sans_serif.woff2") format("woff2");
  font-weight: normal;
  font-style: normal;
}

@font-face {
  font-family: "Pixelated MS Sans Serif";
  src: url("fonts/converted/ms_sans_serif_bold.woff") format("woff");
  src: url("fonts/converted/ms_sans_serif_bold.woff2") format("woff2");
  font-weight: bold;
  font-style: normal;
}

body {
  font-family: Arial;
  font-size: 12px;
  color: var(--text-color);
}

button,
label,
input,
legend,
textarea,
select,
option,
table,
ul.tree-view,
.window,
.title-bar,
li[role=tab] {
  font-family: "Pixelated MS Sans Serif", Arial;
  -webkit-font-smoothing: none;
  font-size: 11px;
}

h1 {
  font-size: 5rem;
}

h2 {
  font-size: 2.5rem;
}

h3 {
  font-size: 2rem;
}

h4 {
  font-size: 1.5rem;
}

u {
  text-decoration: none;
  border-bottom: 0.5px solid #222222;
}

button,
input[type="submit"],
input[type="reset"] {
  box-sizing: border-box;
  border: none;
  color: transparent;
  text-shadow: 0 0 var(--text-color);
  background: var(--surface);
  box-shadow: var(--border-raised-outer), var(--border-raised-inner);
  border-radius: 0;

  min-width: 75px;
  min-height: 23px;
  padding: 0 12px;
}

button.default,
input[type="submit"].default,
input[type="reset"].default {
  box-shadow: var(--default-button-border-raised-outer), var(--default-button-border-raised-inner);
}

.vertical-bar {
  width: 4px;
  height: 20px;
  background: #c0c0c0;
  box-shadow: var(--border-raised-outer), var(--border-raised-inner);
}

button:not(:disabled):active,
input[type="submit"]:not(:disabled):active,
input[type="reset"]:not(:disabled):active {
  box-shadow: var(--border-sunken-outer), var(--border-sunken-inner);
  text-shadow: 1px 1px var(--text-color);
}

button.default:not(:disabled):active,
input[type="submit"].default:not(:disabled):active,
input[type="reset"].default:not(:disabled):active {
  box-shadow: var(--default-button-border-sunken-outer), var(--default-button-border-sunken-inner);
}

@media (not(hover)) {
  button:not(:disabled):hover,
  input[type="submit"]:not(:disabled):hover,
  input[type="reset"]:not(:disabled):hover {
    box-shadow: var(--border-sunken-outer), var(--border-sunken-inner);
  }
}

button:focus,
input[type="submit"]:focus,
input[type="reset"]:focus {
  outline: 1px dotted #000000;
  outline-offset: -4px;
}

button::-moz-focus-inner,
input[type="submit"]::-moz-focus-inner,
input[type="reset"]::-moz-focus-inner {
  border: 0;
}

:disabled,
:disabled + label,
input[readonly],
input[readonly] + label {
  color: var(--button-shadow);
}

button:disabled,
input[type="submit"]:disabled,
input[type="reset"]:disabled,
:disabled + label {
  text-shadow: 1px 1px 0 var(--button-highlight);
}

.window {
  box-shadow: var(--border-window-outer), var(--border-window-inner);
  background: var(--surface);
  padding: 3px;
}

.title-bar {
  background: linear-gradient(
    90deg,
    var(--dialog-blue),
    var(--dialog-blue-light)
  );
  padding: 3px 2px 3px 3px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.title-bar.inactive {
  background: linear-gradient(
    90deg,
    var(--dialog-gray),
    var(--dialog-gray-light)
  );
}

.title-bar-text {
  font-weight: bold;
  color: white;
  letter-spacing: 0;
  margin-right: 24px;
}

.title-bar-controls {
  display: flex;
}

.title-bar-controls button {
  padding: 0;
  display: block;
  min-width: 16px;
  min-height: 14px;
}

.title-bar-controls button:active {
  padding: 0;
}

.title-bar-controls button:focus {
  outline: none;
}

.title-bar-controls button[aria-label="Minimize"],
.title-bar-controls button[aria-label].minimize {
  background-image: svg-load("./icon/minimize.svg");
  background-repeat: no-repeat;
  background-position: bottom 3px left 4px;
}

.title-bar-controls button[aria-label="Maximize"],
.title-bar-controls button[aria-label].maximize {
  background-image: svg-load("./icon/maximize.svg");
  background-repeat: no-repeat;
  background-position: top 2px left 3px;
}

.title-bar-controls button[aria-label="Maximize"]:disabled,
.title-bar-controls button[aria-label].maximize:disabled {
  background-image: svg-load("./icon/maximize-disabled.svg");
  background-repeat: no-repeat;
  background-position: top 2px left 3px;
}

.title-bar-controls button[aria-label="Restore"],
.title-bar-controls button[aria-label].restore {
  background-image: svg-load("./icon/restore.svg");
  background-repeat: no-repeat;
  background-position: top 2px left 3px;
}

.title-bar-controls button[aria-label="Help"],
.title-bar-controls button[aria-label].help {
  background-image: svg-load("./icon/help.svg");
  background-repeat: no-repeat;
  background-position: top 2px left 5px;
}

.title-bar-controls button[aria-label="Close"],
.title-bar-controls button[aria-label].close {
  margin-left: 2px;
  background-image: svg-load("./icon/close.svg");
  background-repeat: no-repeat;
  background-position: top 3px left 4px;
}

.status-bar {
  margin: 0px 1px;
  display: flex;
  gap: 1px;
}

.status-bar-field {
  box-shadow: var(--border-status-field);
  flex-grow: 1;
  padding: 2px 3px;
  margin: 0;
}

.window-body {
  margin: var(--element-spacing);
}

fieldset {
  border-image: svg-load("./icon/groupbox-border.svg") 2;
  padding: calc(2 * var(--border-width) + var(--element-spacing));
  padding-block-start: var(--element-spacing);
  margin: 0;
}

legend {
  background: var(--surface);
}

.field-row {
  display: flex;
  align-items: center;
}

[class^="field-row"] + [class^="field-row"] {
  margin-top: var(--grouped-element-spacing);
}

.field-row > * + * {
  margin-left: var(--grouped-element-spacing);
}

.field-row-stacked {
  display: flex;
  flex-direction: column;
}

.field-row-stacked * + * {
  margin-top: var(--grouped-element-spacing);
}

label {
  display: inline-flex;
  align-items: center;
  user-select: none;
}

input[type="radio"],
input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  margin: 0;
  background: 0;
  position: fixed;
  opacity: 0;
  border: none;
}

input[type="radio"] + label,
input[type="checkbox"] + label {
  line-height: 13px;
}

input[type="radio"] + label {
  position: relative;
  margin-left: var(--radio-total-width);
}

input[type="radio"] + label::before {
  content: "";
  position: absolute;
  top: 0;
  left: calc(-1 * (var(--radio-total-width-precalc)));
  display: inline-block;
  width: var(--radio-width);
  height: var(--radio-width);
  margin-right: var(--radio-label-spacing);
  background: svg-load("./icon/radio-border.svg");
}

input[type="radio"]:active + label::before {
  background: svg-load("./icon/radio-border-disabled.svg");
}

input[type="radio"]:checked + label::after {
  content: "";
  display: block;
  width: var(--radio-dot-width);
  height: var(--radio-dot-width);
  top: var(--radio-dot-top);
  left: var(--radio-dot-left);
  position: absolute;
  background: svg-load("./icon/radio-dot.svg");
}

input[type="radio"]:focus + label,
input[type="checkbox"]:focus + label {
  outline: 1px dotted #000000;
}

input[type="radio"][disabled] + label::before {
  background: svg-load("./icon/radio-border-disabled.svg");
}

input[type="radio"][disabled]:checked + label::after {
  background: svg-load("./icon/radio-dot-disabled.svg");
}

input[type="checkbox"] + label {
  position: relative;
  margin-left: var(--checkbox-total-width);
}

input[type="checkbox"] + label::before {
  content: "";
  position: absolute;
  left: calc(-1 * (var(--checkbox-total-width-precalc)));
  display: inline-block;
  width: var(--checkbox-width);
  height: var(--checkbox-width);
  background: var(--button-highlight);
  box-shadow: var(--border-field);
  margin-right: var(--radio-label-spacing);
}

input[type="checkbox"]:active + label::before {
  background: var(--surface);
}

input[type="checkbox"]:checked + label::after {
  content: "";
  display: block;
  width: var(--checkmark-width);
  height: var(--checkmark-width);
  position: absolute;
  left: calc(
    -1 * (var(--checkbox-total-width-precalc)) + var(--checkmark-left)
  );
  background: svg-load("./icon/checkmark.svg");
}

input[type="checkbox"][disabled] + label::before {
  background: var(--surface);
}

input[type="checkbox"][disabled]:checked + label::after {
  background: svg-load("./icon/checkmark-disabled.svg");
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
input[type="tel"],
input[type="number"],
input[type="search"],
select,
textarea {
  padding: 3px 4px;
  border: none;
  box-shadow: var(--border-field);
  background-color: var(--button-highlight);
  box-sizing: border-box;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border-radius: 0;
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
input[type="tel"],
input[type="search"],
select {
  height: 21px;
}
input[type="number"] {
  /* need this 1 pixel to fit the spinner controls in box */
  height: 22px;
}
/* clears the ‘X’ from Internet Explorer */
input[type=search]::-ms-clear { display: none; width : 0; height: 0; }
input[type=search]::-ms-reveal { display: none; width : 0; height: 0; }
/* clears the ‘X’ from Chrome */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }

input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
input[type="tel"],
input[type="number"],
input[type="search"] {
  /* For some reason descenders are getting cut off without this */
  line-height: 2;
}

input[type="email"]:disabled,
input[type="url"]:disabled,
input[type="tel"]:disabled,
input[type="password"]:disabled,
input[type="text"]:disabled,
input[type="number"]:disabled,
input[type="search"]:disabled,
input[type="email"]:read-only,
input[type="url"]:read-only,
input[type="tel"]:read-only,
input[type="password"]:read-only,
input[type="text"]:read-only,
input[type="number"]:read-only,
input[type="search"]:read-only,
textarea:disabled {
  background-color: var(--surface);
}

select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  position: relative;
  padding-right: 32px;
  background-image: svg-load("./icon/button-down.svg");
  background-position: top 2px right 2px;
  background-repeat: no-repeat;
  border-radius: 0;
}

select:focus,
input[type="text"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="tel"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
textarea:focus {
  outline: none;
}

input[type="range"] {
  -webkit-appearance: none;
  width: 100%;
  background: transparent;
}

input[type="range"]:focus {
  outline: none;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  height: 21px;
  width: 11px;
  background: svg-load("./icon/indicator-horizontal.svg");
  transform: translateY(-8px);
  box-shadow: none;
  border: none;
}

input[type="range"].has-box-indicator::-webkit-slider-thumb {
  background: svg-load("./icon/indicator-rectangle-horizontal.svg");
  transform: translateY(-10px);
}

input[type="range"]::-moz-range-thumb {
  height: 21px;
  width: 11px;
  border: 0;
  border-radius: 0;
  background: svg-load("./icon/indicator-horizontal.svg");
  transform: translateY(2px);
}

input[type="range"].has-box-indicator::-moz-range-thumb {
  background: svg-load("./icon/indicator-rectangle-horizontal.svg");
  transform: translateY(0px);
}

input[type="range"]::-webkit-slider-runnable-track {
  width: 100%;
  height: 2px;
  box-sizing: border-box;
  background: black;
  border-right: 1px solid grey;
  border-bottom: 1px solid grey;
  box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey,
    -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey;
}

input[type="range"]::-moz-range-track {
  width: 100%;
  height: 2px;
  box-sizing: border-box;
  background: black;
  border-right: 1px solid grey;
  border-bottom: 1px solid grey;
  box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey,
    -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey;
}

.is-vertical {
  display: inline-block;
  width: 4px;
  height: 150px;
  transform: translateY(50%);
}

.is-vertical > input[type="range"] {
  width: 150px;
  height: 4px;
  margin: 0 calc(var(--grouped-element-spacing) + var(--range-spacing)) 0
    var(--range-spacing);
  transform-origin: left;
  transform: rotate(270deg) translateX(calc(-50% + var(--element-spacing)));
}

.is-vertical > input[type="range"]::-webkit-slider-runnable-track {
  border-left: 1px solid grey;
  border-right: 0;
  border-bottom: 1px solid grey;
  box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey,
    1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey;
}

.is-vertical > input[type="range"]::-moz-range-track {
  border-left: 1px solid grey;
  border-right: 0;
  border-bottom: 1px solid grey;
  box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey,
    1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey;
}

.is-vertical > input[type="range"]::-webkit-slider-thumb {
  transform: translateY(-8px) scaleX(-1);
}

.is-vertical > input[type="range"].has-box-indicator::-webkit-slider-thumb {
  transform: translateY(-10px) scaleX(-1);
}

.is-vertical > input[type="range"]::-moz-range-thumb {
  transform: translateY(2px) scaleX(-1);
}

.is-vertical > input[type="range"].has-box-indicator::-moz-range-thumb {
  transform: translateY(0px) scaleX(-1);
}

select:focus {
  color: var(--button-highlight);
  background-color: var(--dialog-blue);
}
select:focus option {
  color: #000;
  background-color: #fff;
}

select:active {
  background-image: svg-load("./icon/button-down-active.svg");
}

a {
  color: var(--link-blue);
}

a:focus {
  outline: 1px dotted var(--link-blue);
}

ul.tree-view {
  display: block;
  background: var(--button-highlight);
  box-shadow: var(--border-field);
  padding: 6px;
  margin: 0;
}

ul.tree-view li {
  list-style-type: none;
}

ul.tree-view a {
  text-decoration: none;
  color: #000;
}

ul.tree-view a:focus {
  background-color: var(--dialog-blue);
  color: var(--button-highlight);
}

ul.tree-view ul,
ul.tree-view li {
  margin-top: 3px;
}

ul.tree-view ul {
  margin-left: 16px;
  padding-left: 16px;
  /* Goes down too far */
  border-left: 1px dotted #808080;
}

ul.tree-view ul > li {
  position: relative;
}
ul.tree-view ul > li::before {
  content: "";
  display: block;
  position: absolute;
  left: -16px;
  top: 6px;
  width: 12px;
  border-bottom: 1px dotted #808080;
}

/* Cover the bottom of the left dotted border */
ul.tree-view ul > li:last-child::after {
  content: "";
  display: block;
  position: absolute;
  left: -20px;
  top: 7px;
  bottom: 0px;
  width: 8px;
  background: var(--button-highlight);
}

ul.tree-view details {
  margin-top: 0;
}

ul.tree-view details[open] summary {
  margin-bottom: 0;
}

ul.tree-view ul details > summary:before {
  margin-left: -22px;
  position: relative;
  z-index: 1;
}

ul.tree-view details > summary:before {
  text-align: center;
  display: block;
  float: left;
  content: "+";
  border: 1px solid #808080;
  width: 8px;
  height: 9px;
  line-height: 8px;
  margin-right: 5px;
  padding-left: 1px;
  background-color: #fff;
}

ul.tree-view details[open] > summary:before {
  content: "-";
}

ul.tree-view details > summary::marker,
ul.tree-view details > summary::-webkit-details-marker {
  content: "";
}

pre {
  display: block;
  background: var(--button-highlight);
  box-shadow: var(--border-field);
  padding: 12px 8px;
  margin: 0;
}

code,
code * {
  font-family: monospace;
}

summary:focus {
  outline: 1px dotted #000000;
}

::-webkit-scrollbar {
  width: 16px;
}
::-webkit-scrollbar:horizontal {
  height: 17px;
}

::-webkit-scrollbar-corner {
  background: var(--button-face);
}

::-webkit-scrollbar-track {
  background-image: svg-load("./icon/scrollbar-background.svg");
}

::-webkit-scrollbar-thumb {
  background-color: var(--button-face);
  box-shadow: var(--border-raised-outer), var(--border-raised-inner);
}

::-webkit-scrollbar-button:horizontal:start:decrement,
::-webkit-scrollbar-button:horizontal:end:increment,
::-webkit-scrollbar-button:vertical:start:decrement,
::-webkit-scrollbar-button:vertical:end:increment {
  display: block;
}

::-webkit-scrollbar-button:vertical:start {
  height: 17px;
  background-image: svg-load("./icon/button-up.svg");
}
::-webkit-scrollbar-button:vertical:end {
  height: 17px;
  background-image: svg-load("./icon/button-down.svg");
}
::-webkit-scrollbar-button:horizontal:start {
  width: 16px;
  background-image: svg-load("./icon/button-left.svg");
}
::-webkit-scrollbar-button:horizontal:end {
  width: 16px;
  background-image: svg-load("./icon/button-right.svg");
}

.window[role=tabpanel] {
  position: relative;
  z-index: 2;
}

menu[role=tablist] {
  position: relative;
  margin: 0 0 -2px 0;
  text-indent: 0;
  list-style-type: none;
  display: flex;
  padding-left: 3px;
}

menu[role=tablist] > li {
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  box-shadow: var(--border-tab);
  z-index: 1;
}

menu[role=tablist] > li[aria-selected=true] {
  padding-bottom: 2px;
  margin-top: -2px;
  background-color: var(--surface);
  position: relative;
  z-index: 8;
  margin-left: -3px;
}

menu[role=tablist] > li > a {
  display: block;
  color: #222;
  margin: 6px;
  text-decoration: none;
}
menu[role=tablist] > li[aria-selected=true] > a:focus {
  outline: none;
}
menu[role=tablist] > li > a:focus {
  outline: 1px dotted #222;
}

menu[role=tablist].multirows > li {
  flex-grow: 1;
  text-align: center;
}
.sunken-panel {
  box-sizing: border-box;
  border: 2px groove transparent;
  border-image: svg-load("./icon/sunken-panel-border.svg") 2;
  overflow: auto;
  background-color: #fff;
}

table {
  border-collapse: collapse;
  position: relative;
  text-align: left;
  white-space: nowrap;
  background-color: #fff;
}

table > thead > tr > * {
  position: sticky;
  top: 0;
  height: 17px;
  box-shadow: var(--border-raised-outer), var(--border-raised-inner);
  background: var(--surface);
  box-sizing: border-box;
  font-weight: normal;
  padding: 0 var(--grouped-element-spacing);
}

table.interactive > tbody > tr {
  cursor: pointer;
}

table > tbody > tr.highlighted {
  color: #fff;
  background-color: var(--dialog-blue);
}

table > tbody > tr > * {
  padding: 0 var(--grouped-element-spacing);
  height: 14px;
}

.progress-indicator {
	height: 32px;
	position: relative;
  box-shadow: var(--border-sunken-inner);
  padding: 4px 4px;
  border: none;
  box-sizing: border-box;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border-radius: 0;
}


.progress-indicator > .progress-indicator-bar {
  height: 100%;
  display: block;
  background-color: var(--dialog-blue);
}

.progress-indicator.segmented > .progress-indicator-bar {
  width: 100%;
  background-color: transparent; /* resets the background color which is set to blue in the non-segmented selector */
  background-image: linear-gradient(
    90deg,
    var(--dialog-blue) 0 16px,
    transparent 0 2px
  );
  background-repeat: repeat;
  background-size: 18px 100%;
}

.field-border {
  background: var(--button-highlight);
  box-shadow: var(--border-field);
  padding: 2px;
}

.field-border-disabled {
  background: var(--surface);
  box-shadow: var(--border-field);
  padding: 2px;
}

.status-field-border {
  background: var(--surface);
  box-shadow: var(--border-status-field);
  padding: 1px;
}
Download .txt
gitextract_f_8nzxj9/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── npm-publish.yml
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── build.js
├── docs/
│   ├── docs.css
│   ├── index.html.ejs
│   └── vs.css
├── fonts/
│   └── src/
│       ├── ms-sans-serif/
│       │   ├── license.txt
│       │   └── readme.txt
│       └── ms-sans-serif-bold/
│           ├── license.txt
│           └── readme.txt
├── now.json
├── package.json
├── server.js
└── style.css
Download .txt
SYMBOL INDEX (3 symbols across 1 files)

FILE: build.js
  function buildCSS (line 13) | function buildCSS() {
  function buildDocs (line 35) | function buildDocs() {
  function build (line 74) | function build() {
Condensed preview — 18 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (84K chars).
[
  {
    "path": ".editorconfig",
    "chars": 294,
    "preview": "# https://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert"
  },
  {
    "path": ".github/workflows/npm-publish.yml",
    "chars": 648,
    "preview": "# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created\n# For "
  },
  {
    "path": ".gitignore",
    "chars": 20,
    "preview": "node_modules/\ndist/\n"
  },
  {
    "path": ".npmignore",
    "chars": 14,
    "preview": "node_modules/\n"
  },
  {
    "path": "LICENSE",
    "chars": 1053,
    "preview": "Copyright 2020 Jordan Scales\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this softw"
  },
  {
    "path": "README.md",
    "chars": 3260,
    "preview": "## 98.css\n\n<a href=\"https://npm.im/98.css\"><img height=\"29\" alt=\"npm\" src=\"https://98badges.now.sh/api/version\" /></a>\n<"
  },
  {
    "path": "build.js",
    "chars": 2112,
    "preview": "#!/usr/bin/env node\nconst dedent = require(\"dedent\");\nconst ejs = require(\"ejs\");\nconst fs = require(\"fs\");\nconst glob ="
  },
  {
    "path": "docs/docs.css",
    "chars": 1908,
    "preview": "body {\n  margin: 0;\n  padding: 0;\n  background: #c0c0c0;\n}\n\nmain {\n  width: 65rem;\n  margin-left: 240px;\n  margin-bottom"
  },
  {
    "path": "docs/index.html.ejs",
    "chars": 41229,
    "preview": "<!doctype html>\n<html>\n<head>\n  <title>98.css - A design system for building faithful recreations of old UIs</title>\n  <"
  },
  {
    "path": "docs/vs.css",
    "chars": 836,
    "preview": "/*\n\nVisual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>\n\n*/\n.hljs {\n  display: "
  },
  {
    "path": "fonts/src/ms-sans-serif/license.txt",
    "chars": 215,
    "preview": "The FontStruction “MS Sans Serif”\n(https://fontstruct.com/fontstructions/show/1384746) by “lou” is licensed\nunder a Crea"
  },
  {
    "path": "fonts/src/ms-sans-serif/readme.txt",
    "chars": 1105,
    "preview": "The font file in this archive was created using Fontstruct the free, online\nfont-building tool.\nThis font was created by"
  },
  {
    "path": "fonts/src/ms-sans-serif-bold/license.txt",
    "chars": 220,
    "preview": "The FontStruction “MS Sans Serif Bold”\n(https://fontstruct.com/fontstructions/show/1384862) by “lou” is licensed\nunder a"
  },
  {
    "path": "fonts/src/ms-sans-serif-bold/readme.txt",
    "chars": 1105,
    "preview": "The font file in this archive was created using Fontstruct the free, online\nfont-building tool.\nThis font was created by"
  },
  {
    "path": "now.json",
    "chars": 37,
    "preview": "{\n  \"version\": 2,\n  \"public\": true\n}\n"
  },
  {
    "path": "package.json",
    "chars": 1127,
    "preview": "{\n  \"name\": \"98.css\",\n  \"version\": \"0.1.21\",\n  \"description\": \"A design system for building faithful recreations of old "
  },
  {
    "path": "server.js",
    "chars": 411,
    "preview": "const chokidar = require(\"chokidar\");\nconst build = require(\"./build\");\n\nchokidar\n  .watch([\"style.css\", \"build.js\", \"do"
  },
  {
    "path": "style.css",
    "chars": 23148,
    "preview": "/**\n * 98.css\n * Copyright (c) 2020 Jordan Scales <thatjdanisso.cool>\n * https://github.com/jdan/98.css/blob/main/LICENS"
  }
]

About this extraction

This page contains the full source code of the jdan/98.css GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 18 files (76.9 KB), approximately 21.0k tokens, and a symbol index with 3 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!