/* ========================================================================== OpenCD — CD Jewel Case CSS Framework (Production) Author: B.A. Baracus Base: Open Props v2 via unpkg Principle: Zero magic numbers — every value is a --cd-* custom property ASW Semantic: surface layers, grid overlays, data-attribute API ========================================================================== */ @import "https://unpkg.com/open-props"; /* ========================================================================== 1. Custom Properties — All --cd-* Tokens Components MUST NOT reference Open Props directly. Users override these on :root or a scoped container to theme. ========================================================================== */ :root { /* ═══════════════════════════════════════════════════════════════════════ Physical CD Dimensions (at 2× scale, ISO 15727) Formula: calc( * 2px / 1mm) = ═══════════════════════════════════════════════════════════════════════ */ --cd-scale: 1; /* --cd-scale: 1 = default 2× display scale. 0.5 = 1×, 2 = 4×, etc. */ --cd-jewel-width: calc(280px * var(--cd-scale)); /* 142 mm × 2 */ --cd-jewel-height: calc(245px * var(--cd-scale)); /* 125 mm × 2 */ --cd-jewel-open-width: calc(560px * var(--cd-scale)); /* 284 mm × 2 */ --cd-disc-diameter: calc(240px * var(--cd-scale)); /* 120 mm × 2 */ --cd-disc-hole: calc(30px * var(--cd-scale)); /* Ø15 mm × 2 */ --cd-leaflet-size: calc(240px * var(--cd-scale)); /* 120 mm sq × 2 */ --cd-spine-width: calc(14px * var(--cd-scale)); /* ~7 mm × 2 */ --cd-tray-width: calc(260px * var(--cd-scale)); /* ~130 mm × 2 */ /* ── Derived aspect ratios ── */ --cd-aspect-jewel: 280 / 245; --cd-aspect-leaflet: 1 / 1; --cd-aspect-disc: 1 / 1; /* ═══════════════════════════════════════════════════════════════════════ Surface Colors (ASW-style, oklch — NOT from Open Props) ═══════════════════════════════════════════════════════════════════════ */ --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 */ /* ── Surface 0 — lightest, used for jewel case body & leaflet pages ── */ --cd-surface-0: var(--gray-0); /* ═══════════════════════════════════════════════════════════════════════ Typography ═══════════════════════════════════════════════════════════════════════ */ --cd-font-neo-grotesque: 'Inter', 'Roboto', 'Helvetica Neue', 'Arial', sans-serif; --cd-font-label: var(--cd-font-neo-grotesque); /* spine, metadata, credits */ --cd-font-body: var(--font-serif); /* leaflet prose */ --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); /* ── Spine font sizes ── */ --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); /* ═══════════════════════════════════════════════════════════════════════ Spacing ═══════════════════════════════════════════════════════════════════════ */ --cd-space-inset: var(--size-fluid-1); --cd-space-stack: var(--size-fluid-2); --cd-space-gutter: var(--size-fluid-3); --cd-space-xs: var(--size-1); /* 4–5px */ --cd-space-sm: var(--size-2); /* 8–10px */ /* ═══════════════════════════════════════════════════════════════════════ 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) ═══════════════════════════════════════════════════════════════════════ */ --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); --cd-advisory-fg: #000; --cd-advisory-fg-inv: #fff; --cd-advisory-border: 2px solid var(--cd-advisory-fg); --cd-advisory-font: 'Impact', 'Arial Black', var(--cd-font-label), sans-serif; /* ═══════════════════════════════════════════════════════════════════════ 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 */ /* ═══════════════════════════════════════════════════════════════════════ Component Shadows (all rgba/rgb values defined here, not inline) ═══════════════════════════════════════════════════════════════════════ */ --cd-page-shadow: 0 1px 3px rgb(0 0 0 / 0.08); --cd-disc-hole-shadow: inset 0 0 3px rgb(0 0 0 / 0.15); --cd-disc-shadow: inset 0 0 8px rgb(0 0 0 / 0.12); /* ═══════════════════════════════════════════════════════════════════════ Borders & Dividers ═══════════════════════════════════════════════════════════════════════ */ --cd-tray-border-top: 1px solid var(--cd-grid-color); --cd-track-border-bot: 1px solid var(--cd-grid-color-alt); --cd-track-num-min-w: 2.5ch; --cd-print-border: 1px solid #ccc; /* ═══════════════════════════════════════════════════════════════════════ Letter Spacing Scale ═══════════════════════════════════════════════════════════════════════ */ --cd-letter-spacing-1: 0.05em; --cd-letter-spacing-2: 0.075em; --cd-letter-spacing-3: 0.1em; /* ═══════════════════════════════════════════════════════════════════════ Motion & Easing ═══════════════════════════════════════════════════════════════════════ */ --cd-transition-duration: 200ms; --cd-ease-flip: cubic-bezier(0.34, 1.56, 0.64, 1); --cd-ease-default: var(--ease-3); /* ═══════════════════════════════════════════════════════════════════════ Print Dimensions ═══════════════════════════════════════════════════════════════════════ */ --cd-print-jewel-width: 142mm; --cd-print-jewel-height: 125mm; /* ═══════════════════════════════════════════════════════════════════════ Grain Texture ═══════════════════════════════════════════════════════════════════════ */ --cd-grain-size-1: 120px; --cd-grain-size-2: 200px; --cd-grain-opacity-1: 0.02; --cd-grain-opacity-2: 0.015; /* ═══════════════════════════════════════════════════════════════════════ Responsive Breakpoints (container query widths) ═══════════════════════════════════════════════════════════════════════ */ --cd-break-sm: 350px; --cd-break-md-min: 351px; --cd-break-md-max: 549px; /* ═══════════════════════════════════════════════════════════════════════ Disc Decoration Ratios ═══════════════════════════════════════════════════════════════════════ */ --cd-disc-hole-scale: 0.6; /* decorative ring inside the hole */ --cd-disc-hole-font-scale: 0.5; /* icon character in the hole */ } /* ========================================================================== 2. Reset ========================================================================== */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } /* ========================================================================== 3. Jewel Case Container (.cd-jewel-case) ========================================================================== */ .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(--cd-surface-0); border-radius: var(--cd-jewel-radius); box-shadow: var(--cd-jewel-shadow); overflow: hidden; position: relative; transition: width var(--cd-transition-duration) var(--cd-ease-default); font-family: var(--cd-font-body); color: var(--cd-text-primary); container-type: inline-size; } .cd-jewel-case--open, .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, .spine-label, .spine-track) ========================================================================== */ .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(--cd-space-sm) var(--cd-space-xs); gap: var(--cd-space-sm); 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(--cd-letter-spacing-3); text-transform: uppercase; } .cd-spine .spine-track { font-size: var(--cd-spine-font-xs); letter-spacing: var(--cd-letter-spacing-1); opacity: 0.8; } /* ── Side spine variant ── */ .cd-spine--side { writing-mode: horizontal-tb; flex-direction: row; } /* ========================================================================== 5. Leaflet Content & Pages (.leaflet-content, .leaflet-page) ========================================================================== */ .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(--cd-surface-0); border-radius: calc(var(--cd-leaflet-radius) / 2); padding: var(--cd-space-inset); display: flex; flex-direction: column; gap: var(--cd-space-sm); box-shadow: var(--cd-page-shadow); 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, .disc-hole) ========================================================================== */ .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: var(--cd-disc-shadow); } .disc-art::before { content: ""; position: absolute; width: var(--cd-disc-hole); aspect-ratio: 1; border-radius: 50%; background: var(--cd-surface-0); box-shadow: var(--cd-disc-hole-shadow); } .disc-hole { position: absolute; width: calc(var(--cd-disc-hole) * var(--cd-disc-hole-scale)); aspect-ratio: 1; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: calc(var(--cd-disc-hole) * var(--cd-disc-hole-font-scale)); color: var(--gray-4); z-index: 1; pointer-events: none; } /* ── Disc sheen variant ── */ .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) ========================================================================== */ .human-advisory { display: flex; flex-direction: column; align-items: center; background: var(--cd-advisory-fg); color: var(--cd-advisory-fg-inv); border: var(--cd-advisory-border); font-family: var(--cd-advisory-font); 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(--cd-space-xs) var(--cd-space-sm); font-size: var(--cd-spine-font-sm); letter-spacing: var(--cd-letter-spacing-3); line-height: 1.2; white-space: nowrap; } .human-advisory .advisory-row--black { background: var(--cd-advisory-fg); color: var(--cd-advisory-fg-inv); } .human-advisory .advisory-row--white { background: var(--cd-advisory-fg-inv); color: var(--cd-advisory-fg); } .human-advisory .advisory-row--red { background: var(--cd-advisory-red); color: var(--cd-advisory-fg-inv); } /* ── Advisory badge red variant ── */ .human-advisory--red .advisory-row--black { background: var(--cd-advisory-red-dark); color: var(--cd-advisory-fg-inv); } .human-advisory--red .advisory-row--white { background: var(--cd-advisory-red); color: var(--cd-advisory-fg-inv); } /* ========================================================================== 8. Back Tray (.back-tray, .tray-credits) ========================================================================== */ .back-tray { display: grid; grid-template-columns: var(--cd-spine-width) 1fr var(--cd-spine-width); background: var(--cd-tray-bg); border-top: var(--cd-tray-border-top); 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(--cd-letter-spacing-2); } .tray-credits ol { list-style: none; counter-reset: track; display: flex; flex-direction: column; gap: var(--cd-space-xs); } .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(--cd-space-xs) 0; border-bottom: var(--cd-track-border-bot); display: flex; gap: var(--cd-space-sm); } .tray-credits ol li::before { content: counter(track, decimal-leading-zero) "."; font-family: var(--cd-font-mono); color: var(--cd-text-muted); min-width: var(--cd-track-num-min-w); } .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(--cd-letter-spacing-1); } .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) ========================================================================== */ .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 (container queries) ========================================================================== */ @container (max-width: var(--cd-break-sm)) { .cd-jewel-case { width: 100% !important; grid-template-columns: 1fr; } .cd-spine { writing-mode: horizontal-tb; flex-direction: row; padding: var(--cd-space-xs) var(--cd-space-sm); 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: var(--cd-break-md-min)) and (max-width: var(--cd-break-md-max)) { .cd-jewel-case { width: 100% !important; max-width: var(--cd-jewel-width); } .leaflet-content { gap: var(--cd-space-sm); } .human-advisory .advisory-row { font-size: var(--cd-spine-font-xs); padding: var(--cd-space-xs) var(--cd-space-sm); } } /* ========================================================================== 12. Print Styles ========================================================================== */ @media print { .cd-jewel-case { width: var(--cd-print-jewel-width); height: var(--cd-print-jewel-height); box-shadow: none; border: var(--cd-print-border); } .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) ========================================================================== */ .cd-grain { background-image: repeating-radial-gradient( circle at 50% 50%, transparent 0 1px, rgb(0 0 0 / var(--cd-grain-opacity-1)) 1px 2px, transparent 2px 4px ), repeating-radial-gradient( circle at 100% 100%, transparent 0 3px, rgb(0 0 0 / var(--cd-grain-opacity-2)) 3px 4px, transparent 4px 8px ); background-size: var(--cd-grain-size-1) var(--cd-grain-size-1), var(--cd-grain-size-2) var(--cd-grain-size-2); }