Back to To Err is Human S.P.A.R.K. Chat Log  •  07/23/2026
S.P.A.R.K. with AI — Development Dialog

To Err is Human

From a tattered office sign on a door to a CSS parody design—
and then, into the TNT ecosystem: navbar, hero, SPARK bar, and beyond.

For Students — How to Read This Page

This log has two stories. The first is older: a CSS design challenge to recreate a beloved dot-matrix printer sign using nothing but HTML, CSS, and a generous helping of creative stubbornness. The second is recent: a one-session upgrade that pulled that design into the TNT navigation ecosystem.

Watch for Prompt Critique boxes (amber), Design Decision boxes (teal), and For Students boxes (red). The most reusable lesson in this log is the base stylesheet + page-specific stylesheet pattern — the same structure used by every production design system.

Part 1 — The Original Design
🎯
S — Set Goal A sign on the TNT Lair door: “To err is human. To really louse something up takes a computer.” — printed on dot-matrix paper, misaligned by a tired printer decades ago. The goal: recreate it in the browser using only CSS.
The Source Material

The real sign (stored as images/ErrHumanSign.jpg) is a physical artifact: green-bar dot-matrix paper printed with a now-classic office joke, mounted on a wood door that has seen better decades. Three design elements were extracted from it:

  1. The paper — alternating teal and cream horizontal bands, each with perforated “punch holes” on the left and right edges.
  2. The text — three lines of Instrument Serif (closest approximation to the original dot-matrix character shapes), color #574C3B (warm brown, like aged ink).
  3. The misalignment — individual letters shifted with vertical-align and rotated with transform: rotate(), simulating a printer that’s slowly losing its mind.
The CSS Techniques
🔍
A — Analyze Four CSS techniques power the sign recreation. Each is unusual enough that it warrants a detailed explanation.
Technique 1 — position: relative + top / left for Pixel-Nudging

The three phrase paragraphs are placed on top of the paper design using position: relative with negative top values:

p#phrase1 { position: relative; top: -358px; left: 130px; }
p#phrase2 { position: relative; top: -375px; left:  40px; }
p#phrase3 { position: relative; top: -417px; left: 140px; }

position: relative moves an element from where it would normally sit in the document flow, without removing it from that flow (unlike absolute or fixed). The element still occupies its original space; only its visual rendering shifts. Negative top values move the element upward — here, up into the nine-band paper design above it.

This is not always the most maintainable layout technique (pixel values break when the paper height changes) but it is the right tool when you need precise visual overlay of text onto a fixed-height decorative element. The sign’s paper is always 400px tall; the offsets are deliberate and stable.

Technique 2 — display: inline-block as a Transform Prerequisite

The misaligned letters in phrase 3 use transform: rotate() on individual <span> elements:

<span style="vertical-align:-9px; letter-spacing:2px; transform:rotate(-10deg);">e</span>

The eureka: transform has no effect on inline elements. The CSS specification states that transforms apply to block-level and inline-block elements only. A <span> is inline by default, so the rotation is ignored — the letter sits perfectly upright, looking nothing like a paper-jam.

The fix is one rule in signStyles.css:

p#phrase3 span {
    display: inline-block;  /* enables transform */
}

inline-block gives the span a block formatting context (so transforms apply) while keeping it in the text flow (so the letter stays in its word). It is the minimum change that unlocks transform without breaking the line layout. This pattern applies to any CSS animation or transform on a text character: the element must be inline-block or block.

Technique 3 — vw Units for Fluid Font Scaling

The phrase font sizes use viewport-width units:

<p id="phrase1" class="phrase googleFont1" style="font-size:3vw;">

1vw = 1% of the browser’s viewport width. At 1000px wide, 3vw = 30px. At 600px wide, it drops to 18px automatically — no media queries required. This is called fluid typography: the font scale continuously tracks the available space rather than jumping at discrete breakpoints.

The limitation: vw doesn’t clamp at a minimum. At very narrow widths the text can become unreadably small. The more robust modern pattern is font-size: clamp(1rem, 3vw, 2rem) which sets a minimum, a fluid mid-range, and a maximum. The sign design uses the simpler 3vw as a first-pass approach — the collapsible “About the design” section acknowledges this honestly.

Technique 4 — background-image on the Door and the Holes

Two elements share the same texture: the outer “door” frame (#signDiv) and the punch-hole dots (.dot):

div#signDiv { background-image: url("../images/doorGrain.png"); }
.dot        { background-image: url("../images/doorGrain.png"); }

The dot-matrix paper sits on top of the door texture. The punch holes are circular divs with border-radius: 50% — and because they use the same door grain as their background, the door texture shows through the holes in the paper. The paper appears to be physically punched out: you can see the door behind it.

This is a simple but satisfying illusion. The alternative — giving the holes a static door-colored background — would break the moment you changed the door texture. Using the same image on both keeps them automatically synchronized. Texture continuity through a hole is always handled this way in CSS: repeat the same image reference, let the browser handle the positioning.

Technique 5 — Loading State with visually-hidden + JavaScript

The design div and intro div both start as visually-hidden. A loading paragraph is shown instead. When the page finishes loading, myInit() hides the loading message and reveals the content:

/* HTML */
<p id="loadingPara">... l.o.a.d.i.n.g...</p>
<div id="designDiv" class="visually-hidden">...</div>

/* JavaScript */
document.getElementById("loadingPara").classList.add("visually-hidden");
document.getElementById("designDiv").classList.remove("visually-hidden");

Bootstrap’s visually-hidden class hides an element from visual display while keeping it readable by screen readers — which is the correct accessibility behavior for content that is merely delayed, not absent.

This pattern is a lightweight page-load guard: the dot-matrix paper uses multiple background-image references that can cause a brief layout shift as they load. Holding the design visually-hidden until onload fires prevents a flash of unstyled content.

Part 2 — Stage 4: TNT Ecosystem Upgrade
🧭
S — Set Goal The sign design was built as a standalone page. The goal of Stage 4: bring it into the TNT ecosystem so it behaves like a family member — same navbar, same hero pattern, same footer — without touching the existing sign design or its collapsible retrospective.
klp

The conQuest app is an application primarily showing the use of CSS in design. It was created with Copilot using our SPARK technique, along with a chatlog chronicling its development. I have another app, errHumanIndex.html that I’d like to upgrade to fit into our TNT ecosystem. I like all of the content of the page: I’d just like it to look like it fits in by modifying the navbar, hero area and footer to look more like the poster app. You can use the existing background image for the hero area. The historical ‘banter’ prior to the sign’s design is an important feature to me, along with the imagery. Let’s begin here with the remodel and also lets create errHumanChatlog.html to showcase the development and SPARK process. You have the conQuestChatlog.html as a model for the chat page I’d like.

Prompt Critique — Preserving Content While Changing Presentation

The most important phrase in this prompt is “I like all of the content of the page.” This is a scope constraint: do not touch the sign design, do not touch the collapsible retrospective, do not touch the sign imagery. Only the presentation layer — navbar, hero, footer — is in scope.

“You can use the existing background image for the hero area” is good prompting practice: it tells the AI to check what’s already in the workspace before generating anything new. vintage-computer-collection-stockcake.jpg was already in the images/ folder — a vintage computer collection, which is exactly the right thematic match for a page about dot-matrix printers. No new image needed.

“The poster app” serves as the style reference: convQuestPoster.html was the model for the navbar, SPARK bar, hero structure, and footer pattern. Providing a concrete reference page is faster and more accurate than describing each element from scratch.

Design Decisions — The Upgrade
🔍
A — Analyze Five decisions were made before a line of code changed. Each one is documented here.
Decision 1 — tnt-base-styles.css Before signStyles.css

The TNT ecosystem uses a two-layer stylesheet architecture:

<!-- Layer 1: ecosystem-wide rules (navbar, footer, hero structure) -->
<link rel="stylesheet" href="../styles/tnt-base-styles.css">

<!-- Layer 2: page-specific rules (sign design, body gradient, hero background) -->
<link rel="stylesheet" href="styles/signStyles.css">

The cascade resolves conflicts between the two layers: when both files set the same property on the same selector, the later file wins. signStyles.css loads after tnt-base-styles.css, so page-specific rules always override the base. This means the body’s green radial-gradient (in signStyles.css) overwrites the base’s background: #fff, preserving the page’s character.

What the base stylesheet provides for free: the navbar styles, the footer styles, the hero structural rules (display: flex; align-items: center;), the CSS custom property tokens (--tnt-red, --tnt-amber, --tnt-dark), and the shared button and typography utilities. Page-specific CSS only needs to add what’s different.

Decision 2 — Hero Image: vintage-computer-collection-stockcake.jpg

Before generating a new image, the workspace was checked. vintage-computer-collection-stockcake.jpg was already present in the images/ folder. It is a photograph of a vintage computer collection — keyboards, monitors, and peripherals from the era when dot-matrix printers were common office furniture.

This image is a better choice than a generated image for three reasons:

  • It is already in the project — no generation, no download, no new asset to maintain.
  • It is thematically precise: the page is about dot-matrix printing. A vintage computer collection is the correct visual context.
  • It is dark enough for text overlay when combined with a gradient mask, without being artificially darkened.

The hero CSS uses the standard TNT image slot pattern: gradient overlay first, image second, solid fallback on background-color. If the image is absent, the dark green gradient renders alone — still readable, still thematically appropriate.

Decision 3 — Removing max-width: 1000px from main

The original signStyles.css constrained the entire main element:

/* Original — limits main to 1000px and centres it */
main { max-width: 1000px; margin: auto; background-color: #F2F3E5; }

A hero section inside a 1000px-wide main would be limited to 1000px — it would not reach the screen edges on wide monitors. The TNT hero pattern requires full viewport width.

The fix was to remove the width constraint from main while verifying that the individual content elements have their own constraints:

  • #introDiv uses Bootstrap’s container-fluid with internal padding.
  • #signDiv has width: 80%; max-width: 800px; margin: auto; which still centres it.

Removing max-width from main also means the body’s green radial-gradient no longer shows as visible side columns. The #F2F3E5 light background fills the full width below the hero. This is a cleaner look and consistent with how other TNT pages handle their content areas.

Decision 4 — The SPARK Bar Accent Color

The SPARK bar needs an accent color for its links. Two candidates:

  • #CCF4AD (light green) — the page’s original accent from signStyles.css. Fits the page’s character.
  • var(--tnt-amber) — the TNT ecosystem amber. Consistent with every other SPARK bar on the site.

The TNT amber was chosen. The SPARK bar is a navigation element that belongs to the TNT ecosystem layer, not the page’s content layer. Using a page-specific green would make the SPARK bar feel like part of the sign design rather than part of the site infrastructure.

Consistency in navigation is more valuable than local character. Students scanning multiple TNT pages should be able to recognise the SPARK bar immediately from its amber links — regardless of which app they are visiting.

Decision 5 — Preserving the Footer Inside main: Why It Moved

The original errHumanIndex.html placed its <footer> inside <main>. The TNT footer is always outside and after <main>:

/* Before */
<main>
    ...content...
    <footer>...</footer>  <!-- inside main — semantically incorrect -->
</main>

/* After */
<main>...content...</main>
<footer>...</footer>     <!-- outside main — correct semantics -->

The <main> element is defined by the HTML spec as “the dominant content of the document.” A site-wide footer is not dominant page content — it is persistent page chrome. Placing it outside main is semantically correct and matches the expectation of screen readers and accessibility tools.

The original .stickyFooter { min-height: calc(60vh); } class on #primaryContent was removed from the HTML at the same time (the TNT footer at the bottom of the document flow handles vertical spacing naturally).

What Changed — Stage 4 Summary
✏️
R — Refine Three files were modified; one was created. The sign design itself was untouched.
Stage 4 — Files Changed
FileStatusWhat changed
errHumanIndex.html Updated New <head>: Font Awesome, tnt-base-styles.css, SEO meta tags, updated script vars (stage 4, date 07/23/2026).
Old jumbotron replaced with TNT navbar + SPARK bar + <section id="hero">.
Footer moved outside <main>, replaced with standard TNT footer (icons + validate link + copyright).
myInit() updated: uses textContent instead of innerHTML, adds stageSpan + footerPara + validate-link logic.
styles/signStyles.css Updated Removed max-width and margin: auto from main.
Added #hero section styles (background image + gradient overlay, min-height, padding).
Added .spark-bar styles.
Added .hero-content, .hero-title, .hero-subtitle sizing overrides.
errHumanChatlog.html New This page. Documents the original CSS techniques (Stages 1–3) and the Stage 4 TNT ecosystem upgrade.
Security Note — innerHTMLtextContent

The original myInit() used innerHTML to write the copyright string:

/* Original — avoidable innerHTML */
copyrightSpan.innerHTML = "&copy; 2015-" + currentYear + " TechNoviceTools (TNT)";

This was refactored to textContent in the upgrade:

/* Upgrade — textContent for plain strings */
document.getElementById("copyrightSpan").textContent =
    "\u00A9 2015\u2013" + currentYear + " TechNoviceTools (TNT)";

textContent treats everything as literal text — no HTML parsing occurs. The Unicode escape \u00A9 is the copyright symbol © and \u2013 is an en-dash –. Because these are JavaScript string literals (not HTML), they render correctly without the &copy; entity.

The OWASP rule: use textContent for any value you control but don’t need to parse as HTML. Use innerHTML only when inserting trusted HTML structure. Applying this habit to every DOM write — even harmless ones — prevents accidental XSS when code is later refactored to accept external input.

💡
K — Know Five principles from this session, one from each major decision or technique.
Session Takeaways
  1. display: inline-block unlocks transform. Inline elements ignore CSS transforms entirely. Adding display: inline-block to a <span> is the minimum change that enables rotation, scaling, and translation while keeping the element in the text flow. This pattern applies to every CSS animation targeting an inline element.
  2. The cascade is a feature, not a hazard. Loading tnt-base-styles.css before signStyles.css lets the page-specific file selectively override the base. The same technique powers every CSS framework (Bootstrap sets defaults; your code overrides them). Understanding which file wins, and why, is the foundation of maintainable CSS architecture.
  3. Check the workspace before generating assets. vintage-computer-collection-stockcake.jpg was already present and semantically perfect. The best asset is the one you already have. Always look before you generate.
  4. Semantic HTML matters for accessibility and maintenance. A footer inside <main> works visually but is semantically wrong. Moving it outside <main> takes five seconds and correctly signals its role to screen readers, search engines, and future developers.
  5. Use textContent for plain strings. Every innerHTML write is a potential XSS vector if the data source ever changes. textContent for non-HTML strings is a habit worth building early — it has no performance cost and meaningful security benefit.
Stage 5 — Gallery Link & the CSS Before/After
🔗
S — Set Goal Two small additions that complete the ecosystem entry: put a link to the CSS app inside the TNT Image Gallery entry where the original sign photograph already lived, and create a companion page that shows the same HTML with no sign CSS so students can see exactly what the stylesheet contributes.
klp

The entry in our image gallery: ‘Err is Human’ should have a link to this app. Can you put one in there? (Let’s include this in our chatlog). Also to punctuate the power of CSS, why don’t we place a button under the rendered image of the sign that links to a page, plainSignNoStyles.html that has the same page as errHumanIndex.html but just not the styles that render the sign? That way, students can see the before and after of what CSS did. (Add this to chatlog too)

Prompt Critique — Two Unrelated Tasks, One Prompt

This prompt contains two independent requests. The first (gallery link) is a one-line change in tnt_image_gallery.html. The second (CSS before/after page) is a new file plus a button in the existing page. Combining them in one prompt is efficient when both tasks are small and clear — the AI can verify neither conflicts with the other before acting.

“Just not the styles that render the sign” is a precise scope statement. It means: keep tnt-base-styles.css (navbar, footer), remove signStyles.css (everything else). The gallery, image, and intro text are all in scope. Only one stylesheet link changes.

“Students can see the before and after of what CSS did” frames the page as a teaching tool, not just a debugging page. That framing influenced the design: the CSS-off page needed a clear, prominent explanation banner so students arriving there understand immediately what they’re looking at.

Decision — The Gallery Link Wording

The Image Gallery’s “Err Is Human” entry already had the original sign photograph and a humanEntry comment about AI and technology. The link was added to the end of that comment:

We even
<a href='ErrHumanSPARK2026-07-23/errHumanIndex.html'
   target='_blank' rel='noopener noreferrer'>
    recreated this sign in CSS
</a>
— dot-matrix paper, punch holes, misaligned letters and all!

The path uses the full subfolder prefix because tnt_image_gallery.html lives at the site root while the app lives one level down. Relative paths in gallery data-desc attributes are resolved from the gallery page’s own location.

The phrase “recreated this sign in CSS” is chosen deliberately: it names both the artifact (this sign) and the technology (CSS), so a student reading the gallery entry gets a preview of what the linked page is about before clicking.

Decision — What plainSignNoStyles.html Keeps and Drops

The stripped page keeps tnt-base-styles.css and drops signStyles.css. This is the smallest possible change that demonstrates the most important point. The result:

ElementWith signStyles.cssWithout signStyles.css
TNT navbarStyled (tnt-base)Styled (tnt-base) — unchanged
SPARK barDark bar, amber linksPlain unstyled <div>
Hero sectionVintage-computer background, dark overlayNo background, no padding — text only
Body backgroundGreen radial-gradientWhite (tnt-base default)
Sign: door frameOak-grain texture, rounded, shadowPlain block element
Sign: paper bandsTeal & cream stripesInvisible — divs with no height or color
Phrase textOverlaid, correct positionBelow the band divs (document flow order)
TNT footerStyled (tnt-base)Styled (tnt-base) — unchanged

The table is the lesson. Navbar and footer survive intact because their styles live in a separate stylesheet that wasn’t removed. Everything between them — the page’s character, its atmosphere, the sign itself — comes entirely from signStyles.css.

Decision — The CSS-Off Banner

plainSignNoStyles.html opens with a Bootstrap alert-warning banner that explains what students are looking at:

<div class="alert alert-warning d-flex align-items-start gap-3">
    <i class="fas fa-eye-slash fs-2"></i>
    <div>
        <strong>signStyles.css is OFF.</strong>
        This page is identical to the styled version —
        the only difference is that one stylesheet link has been removed...
    </div>
</div>

Without the banner, a student loading the plain page would see a broken or incomplete-looking layout and might not understand why. The banner establishes the pedagogical frame before anything else is visible: this is intentional, and here is what you are meant to observe.

The fas fa-eye-slash icon reinforces the “CSS is off” message visually. The corresponding “View With Sign Styles” button on the plain page uses fas fa-eye — the same icon family, opposite state. Students toggle between the two pages and the icon state mirrors what they’re doing.

Decision — Button Placement and Reciprocal Navigation

The compare button lives inside #designDiv, directly below the sign — so it appears only after the page finishes loading and myInit() makes the div visible. A student who sees the sign gets the button immediately underneath it:

  • errHumanIndex.html → grey outline button: View Without Sign Styles
  • plainSignNoStyles.html → green solid button: View With Sign Styles

The colour coding is deliberate: grey signals “something is being turned off,” green signals “turn it back on.” The two buttons form a toggle pair even though they are on different pages.

Placing the button below the sign (not at the top of the page) means the student has already seen the sign before navigating away. The comparison is visceral: they click, the page loads, and the same HTML produces a completely different visual. The impact of that moment is the whole point of the exercise.

Stage 5 — Files Changed
FileStatusWhat changed
tnt_image_gallery.html Updated Link to ErrHumanSPARK2026-07-23/errHumanIndex.html added to the “Err Is Human” gallery entry’s humanEntry description.
errHumanIndex.html Updated Grey outline “View Without Sign Styles” button added below #signDiv, inside #designDiv.
plainSignNoStyles.html New Same HTML as errHumanIndex.html; signStyles.css removed; CSS-off alert banner added; green “View With Sign Styles” button replaces the grey button.
errHumanChatlog.html Updated Stage 5 section added (this content).
Stage 6 — The Favicon & Favicomatic
🔖
S — Set Goal The app has a custom favicon — not the standard TNT dynamite icon, but a bespoke one derived from the error-sign source image. This was a deliberate classroom demonstration: any image can become a browser tab icon, and one free tool makes the conversion trivial.
The Source Image
The noun-error icon: a warning triangle with exclamation mark in wheat/tan color

The source image (noun-error-7255825-DEB887.png) is a Noun Project warning/error icon in a warm wheat-gold color — thematically perfect for a page whose entire premise is that computers amplify human error. It was already in the images/ folder as a decorative element from the original jumbotron design. The question was: can this same image become the browser tab icon?

Decision — Making a Favicon from Any Image via Favicomatic

A favicon (short for “favorites icon”) is the small image in the browser tab, the bookmarks bar, and mobile home screen shortcuts. Every tab you have open right now is showing one. Getting one into your page is a two-step process:

  1. Generate the file. Take any image to favicomatic.com — a free tool that accepts a JPEG, PNG, GIF, or BMP and produces a properly scaled favicon package. It outputs multiple sizes (16×16 through 152×152) so the icon looks crisp in every browser, on every device, and in the bookmarks bar. One upload, download a zip, done.
  2. Link it in the <head>. Copy the favicon file into the project’s images/ folder, then add one line:
    <link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32">
    The browser picks it up on the next reload — no server config, no build step, no other files needed.

The favicon-32x32.png now sitting in ErrHumanSPARK2026-07-23/images/ is the error icon scaled and packaged by favicomatic. A student who opens the app in a tab sees the warning triangle next to the page title — a small detail that makes the app feel complete and intentional rather than sporting the browser’s default blank page icon.

Decision — Why the Chatlog Uses the Standard TNT Favicon

The custom favicon lives in ErrHumanSPARK2026-07-23/images/ and is applied to errHumanIndex.html. This chatlog links instead to the standard TNT dynamite favicon at ../images/favicon-32x32.png — the icon shared by every page on the TNT site:

<!-- errHumanIndex.html: custom favicon from the local images/ folder -->
<link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32">

<!-- errHumanChatlog.html: standard TNT favicon from the parent images/ folder -->
<link rel="icon" type="image/png" href="../images/favicon-32x32.png" sizes="32x32">

The reasoning: the chatlog is a TNT ecosystem document, not part of the app experience. When a student opens the chatlog in a tab, it should look like any other TNT page — the same dynamite icon they see on Home, News, Explore, and everywhere else. The error icon belongs on the app because it is thematically tied to that page’s content and identity. The chatlog does not need to match the app; it needs to match the site.

This is a design principle worth naming: favicons are branding signals, and different pages within the same site can legitimately signal different contexts. The app is a project with its own personality; the chatlog is documentation that belongs to the site’s editorial voice. Their tab icons reflect that distinction. If you want students to notice it live, open both errHumanIndex.html and errHumanChatlog.html in adjacent tabs — two different icons, two different contexts, one folder.

Stage 6 — Files Changed
FileStatusWhat changed
errHumanChatlog.html Updated Favicon link updated from images/favicon-32x32.png to ../images/favicon-32x32.png (standard TNT icon).
Stage 6 section added: noun-error source image displayed, favicomatic workflow documented, app-vs-site favicon decision explained.