diff --git a/opencd.css b/opencd.css new file mode 100644 index 0000000..1042f8e --- /dev/null +++ b/opencd.css @@ -0,0 +1,623 @@ +/* ========================================================================== + OpenCD — Jewel Case CSS Framework + Prototype: single-file system + Author: H.M. Murdock + Base: Open Props v2 via unpkg + ========================================================================== */ + +@import "https://unpkg.com/open-props"; + +/* ========================================================================== + 1. Custom Properties — CD Dimension & Design Tokens + ========================================================================== */ + +:root { + /* ── Scale ── + --cd-scale: 1 → default 2× display scale (280px = 142mm at 2×) + Set to 0.5 for 1× (physical mm → px at 96dpi), 2 for 4×, etc. + */ + --cd-scale: 1; + + /* ── Physical CD Dimensions (at 2× scale) ── */ + --cd-jewel-width: calc(280px * var(--cd-scale)); + --cd-jewel-height: calc(245px * var(--cd-scale)); + --cd-jewel-open-width: calc(560px * var(--cd-scale)); + --cd-disc-diameter: calc(240px * var(--cd-scale)); + --cd-disc-hole: calc(30px * var(--cd-scale)); /* Ø15mm × 2 */ + --cd-leaflet-size: calc(240px * var(--cd-scale)); + --cd-spine-width: calc(14px * var(--cd-scale)); + --cd-tray-width: calc(260px * var(--cd-scale)); + + /* ── Derived aspect ratios ── */ + --cd-aspect-jewel: 280 / 245; + --cd-aspect-leaflet: 1 / 1; + --cd-aspect-disc: 1 / 1; + + /* ── Surface Colors (ASW-style, NOT from Open Props — Amy finding #1) ── */ + --cd-surface-1: oklch(30% .015 265); /* tray paper base */ + --cd-surface-2: oklch(35% .015 265); /* tray raised panel */ + --cd-surface-3: oklch(40% .015 265); /* leaflet inner area */ + --cd-surface-4: oklch(15% .01 265); /* spine background — darkest */ + + /* ── Typography ── */ + --cd-font-label: var(--font-neo-grotesque); /* Inter/Roboto stack — Amy finding #4 */ + --cd-font-body: var(--font-serif); + --cd-font-mono: var(--font-mono-code, var(--font-mono)); + --cd-font-size-body: var(--font-size-fluid-1); + --cd-font-size-title: var(--font-size-fluid-2); + --cd-font-size-display: var(--font-size-fluid-3); + + /* ── Spacing insets ── */ + --cd-space-inset: var(--size-fluid-1); + --cd-space-stack: var(--size-fluid-2); + --cd-space-gutter: var(--size-fluid-3); + + /* ── Semantic Text Colors ── */ + --cd-text-primary: var(--gray-9); + --cd-text-secondary: var(--gray-7); + --cd-text-muted: var(--gray-5); + --cd-text-on-spine: var(--gray-1); + + /* ── Surface / Tray Mappings ── */ + --cd-tray-bg: var(--cd-surface-1); + --cd-tray-bg-raised: var(--cd-surface-2); + --cd-tray-bg-sunken: var(--cd-surface-3); + --cd-spine-bg: var(--cd-surface-4); + + /* ── Grid Colors (custom — NOT Open Props tokens, Amy finding #2) ── */ + --cd-grid-color: var(--gray-3); + --cd-grid-color-alt: var(--gray-2); + --cd-grid-fine: 4px; + --cd-grid-coarse: 8px; + + /* ── Advisory Badge ── */ + --cd-advisory-red: var(--red-6); + --cd-advisory-red-dark: var(--red-7); + --cd-advisory-bg: var(--red-0); + + /* ── Jewel Case Decorations ── */ + --cd-jewel-radius: var(--radius-2); /* 5px */ + --cd-jewel-shadow: var(--shadow-2); + --cd-jewel-shadow-raised: var(--shadow-3); + --cd-leaflet-radius: var(--radius-3); /* 1rem */ + + /* ── Spine Typography ── */ + --cd-spine-font-xs: var(--font-size-0); + --cd-spine-font-sm: var(--font-size-1); + --cd-spine-font-md: var(--font-size-2); + --cd-spine-font-lg: var(--font-size-3); + + /* ── Motion & Print ── */ + --cd-transition-duration: 200ms; + --cd-ease-flip: cubic-bezier(0.34, 1.56, 0.64, 1); + --cd-print-jewel-width: 142mm; + --cd-print-jewel-height: 125mm; +} + +/* ========================================================================== + 2. Reset + ========================================================================== */ + +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +/* ========================================================================== + 3. Jewel Case Container + ========================================================================== */ + +.cd-jewel-case { + display: grid; + grid-template-columns: var(--cd-spine-width) 1fr; + grid-template-rows: auto 1fr; + width: var(--cd-jewel-width); + min-height: var(--cd-jewel-height); + background: var(--gray-0); + border-radius: var(--cd-jewel-radius); + box-shadow: var(--cd-jewel-shadow); + overflow: hidden; + position: relative; + transition: width var(--cd-transition-duration) var(--ease-3); + font-family: var(--cd-font-body); + color: var(--cd-text-primary); + container-type: inline-size; +} + +.cd-jewel-case--open { + width: var(--cd-jewel-open-width); +} + +.cd-jewel-case[data-jewel-state="open"] { + width: var(--cd-jewel-open-width); +} + +/* ── Internal layout wrapper ── */ +.cd-jewel-case > .cd-jewel-inner { + grid-column: 2; + grid-row: 1 / -1; + display: flex; + flex-direction: column; + padding: var(--cd-space-inset); + gap: var(--cd-space-stack); + min-height: 0; +} + +/* ========================================================================== + 4. Spine + ========================================================================== */ + +.cd-spine { + grid-column: 1; + grid-row: 1 / -1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: var(--cd-spine-bg); + color: var(--cd-text-on-spine); + font-family: var(--cd-font-label); + padding: var(--size-2) var(--size-1); + gap: var(--size-2); + writing-mode: vertical-rl; + text-orientation: mixed; + user-select: none; +} + +.cd-spine .spine-label { + font-size: var(--cd-spine-font-sm); + font-weight: 600; + letter-spacing: var(--font-letterspacing-3, 0.1em); + text-transform: uppercase; +} + +.cd-spine .spine-track { + font-size: var(--cd-spine-font-xs); + letter-spacing: var(--font-letterspacing-1, 0.05em); + opacity: 0.8; +} + +/* ── Side spine variant ── */ +.cd-spine--side { + writing-mode: horizontal-tb; + flex-direction: row; +} + +/* ========================================================================== + 5. Leaflet Content & Pages + ========================================================================== */ + +.leaflet-content { + display: flex; + flex-direction: column; + gap: var(--cd-space-stack); + max-width: var(--cd-leaflet-size); + position: relative; + background: + repeating-linear-gradient( + 0deg, + transparent 0 calc(var(--cd-grid-coarse) * 3 - 1px), + var(--cd-grid-color) calc(var(--cd-grid-coarse) * 3 - 1px) calc(var(--cd-grid-coarse) * 3) + ), + var(--cd-tray-bg); + border-radius: var(--cd-leaflet-radius); + padding: var(--cd-space-inset); +} + +.leaflet-page { + aspect-ratio: var(--cd-aspect-leaflet); + background: var(--gray-0); + border-radius: calc(var(--cd-leaflet-radius) / 2); + padding: var(--cd-space-inset); + display: flex; + flex-direction: column; + gap: var(--size-2); + box-shadow: 0 1px 3px rgba(0,0,0,.08); + transition: transform var(--cd-transition-duration) var(--cd-ease-flip); + position: relative; +} + +.leaflet-page[data-leaflet-active="true"] { + box-shadow: var(--cd-jewel-shadow); +} + +.leaflet-page[data-leaflet-direction="rtl"] { + direction: rtl; +} + +.leaflet-page h1, +.leaflet-page h2 { + font-family: var(--cd-font-label); + font-size: var(--cd-font-size-title); + color: var(--cd-text-primary); + line-height: 1.2; +} + +.leaflet-page p { + font-family: var(--cd-font-body); + font-size: var(--cd-font-size-body); + color: var(--cd-text-secondary); + line-height: 1.6; +} + +.leaflet-page .leaflet-meta { + font-family: var(--cd-font-mono); + font-size: var(--cd-spine-font-xs); + color: var(--cd-text-muted); + margin-top: auto; +} + +/* ========================================================================== + 6. Disc Art + ========================================================================== */ + +.disc-art { + width: var(--cd-disc-diameter); + aspect-ratio: var(--cd-aspect-disc); + border-radius: 50%; + background: + radial-gradient( + circle at 30% 30%, + var(--gray-4) 0%, + var(--gray-2) 40%, + var(--gray-6) 70%, + var(--gray-2) 100% + ); + display: flex; + align-items: center; + justify-content: center; + position: relative; + box-shadow: inset 0 0 8px rgba(0,0,0,.12); +} + +.disc-art::before { + content: ""; + position: absolute; + width: var(--cd-disc-hole); + aspect-ratio: 1; + border-radius: 50%; + background: var(--gray-0); + box-shadow: inset 0 0 3px rgba(0,0,0,.15); +} + +.disc-hole { + position: absolute; + width: calc(var(--cd-disc-hole) * 0.6); + aspect-ratio: 1; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: calc(var(--cd-disc-hole) * 0.5); + color: var(--gray-4); + z-index: 1; + pointer-events: none; +} + +/* ── Disc art variants ── */ +.disc-art--sheen { + background: + radial-gradient( + circle at 25% 25%, + var(--gray-4) 0%, + var(--gray-2) 35%, + var(--gray-5) 50%, + transparent 65% + ), + radial-gradient( + circle at 75% 75%, + var(--gray-7) 0%, + var(--gray-3) 40%, + transparent 70% + ), + repeating-radial-gradient( + circle at 50%, + transparent 0 calc(var(--cd-disc-hole) * 0.5), + var(--gray-3) calc(var(--cd-disc-hole) * 0.5) calc(var(--cd-disc-hole) * 0.5 + 1px) + ); +} + +/* ========================================================================== + 7. Human Advisory Badge + ========================================================================== */ + +.human-advisory { + display: flex; + flex-direction: column; + align-items: center; + background: #000; + color: #fff; + border: 2px solid #000; + font-family: Impact, "Arial Black", var(--cd-font-label), sans-serif; + text-transform: uppercase; + text-align: center; + padding: 0; + width: fit-content; + max-width: 100%; + position: absolute; + bottom: var(--cd-space-inset); + right: var(--cd-space-inset); +} + +.human-advisory .advisory-row { + width: 100%; + padding: var(--size-1) var(--size-3); + font-size: var(--cd-spine-font-sm); + letter-spacing: var(--font-letterspacing-3, 0.1em); + line-height: 1.2; + white-space: nowrap; +} + +.human-advisory .advisory-row--black { + background: #000; + color: #fff; +} + +.human-advisory .advisory-row--white { + background: #fff; + color: #000; +} + +.human-advisory .advisory-row--red { + background: var(--cd-advisory-red); + color: #fff; +} + +/* ── Human Advisory variants ── */ +.human-advisory--red .advisory-row--black { + background: var(--cd-advisory-red-dark); + color: #fff; +} + +.human-advisory--red .advisory-row--white { + background: var(--cd-advisory-red); + color: #fff; +} + +/* ========================================================================== + 8. Back Tray + ========================================================================== */ + +.back-tray { + display: grid; + grid-template-columns: var(--cd-spine-width) 1fr var(--cd-spine-width); + background: var(--cd-tray-bg); + border-top: 1px solid var(--cd-grid-color); + padding: 0; + position: relative; +} + +.back-tray .tray-credits { + grid-column: 2; + padding: var(--cd-space-inset); + display: flex; + flex-direction: column; + gap: var(--cd-space-stack); + background: var(--cd-tray-bg-raised); + border-radius: 0 0 var(--cd-leaflet-radius) var(--cd-leaflet-radius); +} + +.tray-credits h2 { + font-family: var(--cd-font-label); + font-size: var(--cd-font-size-title); + color: var(--cd-text-primary); + text-transform: uppercase; + letter-spacing: var(--font-letterspacing-2, 0.075em); +} + +.tray-credits ol { + list-style: none; + counter-reset: track; + display: flex; + flex-direction: column; + gap: var(--size-1); +} + +.tray-credits ol li { + counter-increment: track; + font-family: var(--cd-font-label); + font-size: var(--cd-font-size-body); + color: var(--cd-text-secondary); + padding: var(--size-1) 0; + border-bottom: 1px solid var(--cd-grid-color-alt); + display: flex; + gap: var(--size-2); +} + +.tray-credits ol li::before { + content: counter(track, decimal-leading-zero) "."; + font-family: var(--cd-font-mono); + color: var(--cd-text-muted); + min-width: 2.5ch; +} + +.tray-credits .credits-label { + font-family: var(--cd-font-mono); + font-size: var(--cd-spine-font-xs); + color: var(--cd-text-muted); + text-transform: uppercase; + letter-spacing: var(--font-letterspacing-1, 0.05em); +} + +.tray-credits p { + font-family: var(--cd-font-body); + font-size: var(--cd-font-size-body); + color: var(--cd-text-secondary); + line-height: 1.5; +} + +/* ── Back tray spine labels ── */ +.back-tray .cd-spine { + grid-row: 1; + background: var(--cd-spine-bg); +} + +/* ========================================================================== + 9. Grid Overlay Utility + ========================================================================== */ + +.cd-grid { + background-image: + repeating-linear-gradient( + 0deg, + transparent 0 calc(var(--cd-grid-coarse) - 1px), + var(--cd-grid-color) calc(var(--cd-grid-coarse) - 1px) var(--cd-grid-coarse) + ); +} + +.cd-grid--fine { + background-image: + repeating-linear-gradient( + 0deg, + transparent 0 calc(var(--cd-grid-fine) - 1px), + var(--cd-grid-color) calc(var(--cd-grid-fine) - 1px) var(--cd-grid-fine) + ); +} + +.cd-grid--coarse { + background-image: + repeating-linear-gradient( + 0deg, + transparent 0 calc(var(--cd-grid-coarse) - 1px), + var(--cd-grid-color) calc(var(--cd-grid-coarse) - 1px) var(--cd-grid-coarse) + ); +} + +.cd-grid--crosshatch { + background-image: + repeating-linear-gradient( + 0deg, + transparent 0 calc(var(--cd-grid-fine) - 1px), + var(--cd-grid-color-alt) calc(var(--cd-grid-fine) - 1px) var(--cd-grid-fine) + ), + repeating-linear-gradient( + 90deg, + transparent 0 calc(var(--cd-grid-coarse) - 1px), + var(--cd-grid-color) calc(var(--cd-grid-coarse) - 1px) var(--cd-grid-coarse) + ); +} + +/* ========================================================================== + 10. Open / Closed State Transitions + ========================================================================== */ + +.cd-jewel-case .back-tray { + display: none; +} + +.cd-jewel-case--open .back-tray, +.cd-jewel-case[data-jewel-state="open"] .back-tray { + display: grid; +} + +/* ========================================================================== + 11. Responsive Breakpoints (Open Props container queries) + ========================================================================== */ + +@container (max-width: 350px) { + .cd-jewel-case { + width: 100% !important; + grid-template-columns: 1fr; + } + + .cd-spine { + writing-mode: horizontal-tb; + flex-direction: row; + padding: var(--size-1) var(--size-2); + grid-column: 1; + grid-row: 1; + } + + .cd-jewel-inner { + grid-column: 1; + grid-row: 2; + } + + .disc-art { + width: 100% !important; + max-width: var(--cd-disc-diameter); + margin: 0 auto; + } + + .leaflet-content { + max-width: 100%; + } + + .human-advisory { + position: static; + margin-top: var(--cd-space-stack); + align-self: center; + } +} + +@container (min-width: 351px) and (max-width: 549px) { + .cd-jewel-case { + width: 100% !important; + max-width: var(--cd-jewel-width); + } + + .leaflet-content { + gap: var(--size-2); + } + + .human-advisory .advisory-row { + font-size: var(--cd-spine-font-xs); + padding: var(--size-1) var(--size-2); + } +} + +/* ========================================================================== + 12. Print Styles + ========================================================================== */ + +@media print { + .cd-jewel-case { + width: var(--cd-print-jewel-width); + height: var(--cd-print-jewel-height); + box-shadow: none; + border: 1px solid #ccc; + } + + .cd-jewel-case--open { + width: calc(var(--cd-print-jewel-width) * 2); + } + + .back-tray { + display: grid !important; + } + + .human-advisory { + position: absolute; + } + + .disc-art { + box-shadow: none; + } + + .cd-jewel-case, + .leaflet-page, + .back-tray { + border-radius: 0; + } +} + +/* ========================================================================== + 13. Grain Texture Utility + ========================================================================== */ + +.cd-grain { + background-image: repeating-radial-gradient( + circle at 50% 50%, + transparent 0 1px, + rgba(0,0,0,.02) 1px 2px, + transparent 2px 4px + ), + repeating-radial-gradient( + circle at 100% 100%, + transparent 0 3px, + rgba(0,0,0,.015) 3px 4px, + transparent 4px 8px + ); + background-size: 120px 120px, 200px 200px; +} \ No newline at end of file diff --git a/templates/back-tray.html b/templates/back-tray.html new file mode 100644 index 0000000..3539ff0 --- /dev/null +++ b/templates/back-tray.html @@ -0,0 +1,152 @@ + + + + + + OpenCD · Back Tray + + + + + + +
+ +
+ + + + + +
+ + Tracklist +
    +
  1. jewel-case
  2. +
  3. leaflet
  4. +
  5. back-tray
  6. +
  7. human-advisory
  8. +
  9. disc-art
  10. +
  11. spine-navigation
  12. +
  13. grid-overlay
  14. +
  15. print-layout
  16. +
+ + Credits +

+ Design & Architecture
+ Hannibal · Face +

+

+ Engineering & Prototypes
+ Murdock · B.A. Baracus +

+

+ Quality & Verification
+ Amy Amanda Allen +

+ + Technical +

+ Built on Open Props v2 · Pure CSS framework · No build step required
+ ISO 15727 jewel case dimensions · 2× display scale
+ GPG-signed commits · A-Team design collective +

+ +
+ + + + +
+
+ + +
+ + + +
+ +
+ Back tray paper insert (151 × 118 mm physical) with dual spines, tracklist, and production credits · Grid overlay inspired by trentuna.com paper-card aesthetic +
+ + + + \ No newline at end of file diff --git a/templates/jewel-case.html b/templates/jewel-case.html new file mode 100644 index 0000000..2cd6c99 --- /dev/null +++ b/templates/jewel-case.html @@ -0,0 +1,131 @@ + + + + + + OpenCD · Jewel Case + + + + + + +
+ + + + + +
+ + +
+
+

Jewel Case

+

A compact disc (CD) jewel case is a three-piece plastic case designed to hold standard audio CDs, CD-ROMs, and other optical media. This prototype recreates the physical form factor in pure HTML and CSS.

+ 142 × 125 mm · 2× scale +
+
+ + +
+ +
+ + + + +
+
+ + +
+ + + +
+ +
+ An OpenCD prototype by H.M. Murdock · Built with Open Props · Pure CSS, no JS dependency +
+ + + + \ No newline at end of file diff --git a/templates/leaflet.html b/templates/leaflet.html new file mode 100644 index 0000000..766fbfb --- /dev/null +++ b/templates/leaflet.html @@ -0,0 +1,184 @@ + + + + + + OpenCD · Leaflet + + + + + + +
+ +
+ +
+ +
+ +
+

Design Notes

+

This booklet is a demonstration of the leaflet component — the insert booklet found inside a standard CD jewel case. Each page measures 120 × 120 mm (240px at 2× scale), matching the ISO 15727 standard for CD packaging.

+ Page 1 of 4 · v0.1.0 +
+ +
+

Architecture

+

OpenCD is built on Open Props — a design token framework by Adam Argyle. Every dimension, color, and spacing value maps to a custom property, with fallback values for standalone use. The framework includes:

+
    +
  • CD dimension tokens at 2× scale
  • +
  • Semantic color aliases on Open Props
  • +
  • ASW-inspired surface layers
  • +
  • Visible grid overlays (tray paper aesthetic)
  • +
+ Page 2 of 4 · v0.1.0 +
+ +
+

Token System

+

The variable layer defines ~40 custom properties organized into semantic groups:

+
+
--cd-jewel-width
+
280px × scale
+
--cd-surface-1
+
oklch(30% .015 265)
+
--cd-font-label
+
font-neo-grotesque
+
+ Page 3 of 4 · v0.1.0 +
+ +
+

Credits

+

OpenCD is a project of the A-Team design collective — a framework for physical-digital design artifacts that bridge the gap between print packaging and web implementations.

+

Design: Hannibal & Face
Engineering: Murdock & B.A.
Quality: Amy

+ Page 4 of 4 · MMXXV +
+ +
+
+ + + + +
+
+ + +
+ + Page 1 / 4 + +
+ +
+ Leaflet booklet demo · 4-page layout at 120 × 120 mm each · Page-turn via inline JS +
+ + + + \ No newline at end of file