|
- <title>PostcardMojo Logo Files</title>
- <meta name="claude:viewport-fit-sides" content="cover">
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fredoka:wght@500;600&family=Figtree:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap">
- <style>
- /* Layout: brand header, sticky-free control bar, then one comparison row per logo: PNG panel | JPG panel, stacking on narrow screens */
- :root {
- --bg: #f6f5f1;
- --surface: #ffffff;
- --fg: #1a2a3a;
- --muted: #5f6b76;
- --line: #e2dfd6;
- --navy: #1b3a57;
- --gold: #b88a1c;
- --good-bg: #e6f2ea;
- --good-fg: #1f6b3a;
- --warn-bg: #fdeeea;
- --warn-fg: #a3341c;
- --swatch-light: #ffffff;
- --swatch-dark: #172a3d;
- --check-a: #ffffff;
- --check-b: #e8e6e0;
- --focus: #b88a1c;
- --font-display: "Fredoka", "Nunito", system-ui, sans-serif;
- --font-body: "Figtree", system-ui, -apple-system, "Segoe UI", sans-serif;
- --font-mono: "JetBrains Mono", ui-monospace, Consolas, monospace;
- }
- @media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- --bg: #11161c; --surface: #19212a; --fg: #e8ecef; --muted: #9aa6b1; --line: #2a3542;
- --navy: #9cc0e2; --gold: #e2bb55; --good-bg: #17301f; --good-fg: #8fd3a5;
- --warn-bg: #3a1f19; --warn-fg: #f4a48f;
- --check-a: #2a3440; --check-b: #222b35; --focus: #e2bb55; color-scheme: dark;
- }
- }
- :root[data-theme="dark"] {
- --bg: #11161c; --surface: #19212a; --fg: #e8ecef; --muted: #9aa6b1; --line: #2a3542;
- --navy: #9cc0e2; --gold: #e2bb55; --good-bg: #17301f; --good-fg: #8fd3a5;
- --warn-bg: #3a1f19; --warn-fg: #f4a48f;
- --check-a: #2a3440; --check-b: #222b35; --focus: #e2bb55; color-scheme: dark;
- }
-
- body {
- background: var(--bg); color: var(--fg); font-family: var(--font-body); font-size: 15px; line-height: 1.5;
- padding-left: max(16px, env(safe-area-inset-left, 0px));
- padding-right: max(16px, env(safe-area-inset-right, 0px));
- padding-block: 40px 64px;
- }
- .wrap { max-width: 1180px; margin: 0 auto; display: grid; gap: 32px; }
-
- header { display: grid; gap: 8px; }
- h1 { font-family: var(--font-display); font-weight: 600; font-size: 2rem; line-height: 1.15; margin: 0; text-wrap: balance; color: var(--navy); }
- h1 span { color: var(--gold); }
- .lede { margin: 0; color: var(--muted); max-width: 66ch; }
-
- .totals { display: flex; flex-wrap: wrap; gap: 8px 20px; font-size: 0.875rem; color: var(--muted); }
- .totals b { color: var(--fg); font-family: var(--font-mono); font-weight: 500; font-variant-numeric: tabular-nums; }
-
- .controls { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; }
- .ctl { display: flex; align-items: center; gap: 10px; }
- .ctl .label { font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
- .seg { display: inline-flex; border: 1px solid var(--line); border-radius: 999px; padding: 3px; background: var(--surface); }
- .seg button {
- font: inherit; font-size: 0.875rem; font-weight: 500; border: 0; background: transparent; color: var(--muted);
- padding: 6px 14px; border-radius: 999px; cursor: pointer;
- }
- .seg button[aria-pressed="true"] { background: var(--navy); color: var(--bg); }
- button:focus-visible, .panel .view:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
-
- section { display: grid; gap: 14px; }
- h2 { font-family: var(--font-display); font-weight: 500; font-size: 1.25rem; margin: 0; }
- h2 small { font-family: var(--font-body); font-size: 0.875rem; color: var(--muted); font-weight: 400; margin-left: 6px; }
-
- .list { display: grid; gap: 16px; }
- .list.icons { grid-template-columns: repeat(auto-fill, minmax(min(100%, 520px), 1fr)); }
-
- .item { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; display: grid; min-width: 0; }
- .item-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; padding: 12px 14px; border-bottom: 1px solid var(--line); }
- .name { font-family: var(--font-mono); font-size: 0.875rem; font-weight: 500; overflow-wrap: anywhere; }
- .dims { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--muted); font-variant-numeric: tabular-nums; }
- .pill { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; }
- .pill.warn { background: var(--warn-bg); color: var(--warn-fg); }
- .pill.good { background: var(--good-bg); color: var(--good-fg); }
-
- .compare { display: grid; grid-template-columns: 1fr 1fr; }
- .item.wide .compare { grid-template-columns: 1fr; }
- @media (max-width: 640px) { .compare { grid-template-columns: 1fr; } }
- .panel { display: grid; grid-template-rows: auto 1fr; min-width: 0; }
- .panel + .panel { border-left: 1px solid var(--line); }
- .item.wide .panel + .panel { border-left: 0; border-top: 1px solid var(--line); }
- @media (max-width: 640px) { .panel + .panel { border-left: 0; border-top: 1px solid var(--line); } }
- .panel-label { display: flex; justify-content: space-between; gap: 8px; padding: 8px 14px; font-size: 0.8125rem; color: var(--muted); }
- .panel-label .fmt { font-weight: 600; color: var(--fg); letter-spacing: 0.04em; }
- .panel-label .kb { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
- .view { overflow: auto; padding: 24px 20px; display: grid; place-items: center; min-height: 140px; }
- .view img { display: block; max-width: none; height: auto; }
- body[data-zoom="1"] .view img { max-width: 100%; }
- body:not([data-zoom="1"]) .view { place-items: start; }
- body:not([data-zoom="1"]) .view img { image-rendering: pixelated; }
-
- body[data-bg="light"] .view { background: var(--swatch-light); }
- body[data-bg="dark"] .view { background: var(--swatch-dark); }
- body[data-bg="checker"] .view {
- background-color: var(--check-a);
- background-image: linear-gradient(45deg, var(--check-b) 25%, transparent 25%, transparent 75%, var(--check-b) 75%),
- linear-gradient(45deg, var(--check-b) 25%, transparent 25%, transparent 75%, var(--check-b) 75%);
- background-size: 16px 16px; background-position: 0 0, 8px 8px;
- }
-
- footer { color: var(--muted); font-size: 0.8125rem; border-top: 1px solid var(--line); padding-top: 16px; display: grid; gap: 6px; }
- footer p { margin: 0; max-width: 80ch; }
- code { font-family: var(--font-mono); font-size: 0.92em; }
- </style>
-
- <div class="wrap">
- <header>
- <h1>postcard<span>mojo</span> logo files</h1>
- <p class="lede">Each logo as a transparent PNG (left) and a white-background JPG (right). Zoom in to look for compression artifacts. Switch to a dark background to see where the JPG's white box shows.</p>
- <div class="totals" id="totals"></div>
- </header>
-
- <div class="controls">
- <div class="ctl" role="group" aria-label="Preview background">
- <span class="label">Background</span>
- <div class="seg" id="bg-seg">
- <button type="button" id="bg-light" data-bg="light" aria-pressed="true">Light</button>
- <button type="button" id="bg-dark" data-bg="dark" aria-pressed="false">Dark</button>
- <button type="button" id="bg-checker" data-bg="checker" aria-pressed="false">Transparent</button>
- </div>
- </div>
- <div class="ctl" role="group" aria-label="Zoom">
- <span class="label">Zoom</span>
- <div class="seg" id="zoom-seg">
- <button type="button" id="zoom-1" data-zoom="1" aria-pressed="true">Fit</button>
- <button type="button" id="zoom-2" data-zoom="2" aria-pressed="false">2×</button>
- <button type="button" id="zoom-4" data-zoom="4" aria-pressed="false">4×</button>
- </div>
- </div>
- </div>
-
- <section>
- <h2>Full logo <small>card icon with wordmark</small></h2>
- <div class="list" id="lockups"></div>
- </section>
-
- <section>
- <h2>Icon <small>postcard mark only</small></h2>
- <div class="list icons" id="icons"></div>
- </section>
-
- <footer>
- <p>PNGs are in <code>images/logos/png/</code> and JPGs in <code>images/logos/jpg/</code>. Sizes are the actual pixel size of each file. The names come from the labels on the original sheet, which don't match the real sizes.</p>
- <p>At 2× and 4×, scrolling one panel scrolls its partner too, so both show the same spot.</p>
- </footer>
- </div>
-
- <script>
- (function () {
- // w, h = pixels; png, jpg = file size in KB
- var lockups = [
- { file: 'logo_full_large', w: 796, h: 220, png: 216.4, jpg: 26.7, wide: true },
- { file: 'logo_full_medium_c', w: 411, h: 123, png: 68.8, jpg: 12.9 },
- { file: 'logo_full_medium_a', w: 285, h: 88, png: 38.0, jpg: 7.2 },
- { file: 'logo_full_small_b', w: 217, h: 73, png: 24.0, jpg: 4.8 },
- { file: 'logo_full_small_a', w: 187, h: 63, png: 18.7, jpg: 3.9 },
- { file: 'logo_full_medium_b_misprint', w: 535, h: 129, png: 96.1, jpg: 17.7, misprint: true }
- ];
- var icons = [
- { file: 'icon_256', w: 169, h: 129, png: 41.2, jpg: 6.7 },
- { file: 'icon_64', w: 143, h: 85, png: 21.5, jpg: 4.0 },
- { file: 'icon_24', w: 95, h: 81, png: 14.1, jpg: 3.8 },
- { file: 'icon_small_8', w: 90, h: 72, png: 13.9, jpg: 3.0 }
- ];
-
- function el(tag, cls, text) {
- var e = document.createElement(tag);
- if (cls) e.className = cls;
- if (text != null) e.textContent = text;
- return e;
- }
-
- function panel(fmt, src, kb, item) {
- var p = el('div', 'panel');
- var label = el('div', 'panel-label');
- label.append(el('span', 'fmt', fmt), el('span', 'kb', kb.toFixed(1) + ' KB'));
- var view = el('div', 'view');
- view.tabIndex = 0;
- view.setAttribute('aria-label', fmt + ' preview of ' + item.file);
- var img = el('img');
- img.src = src; img.alt = item.file + ' as ' + fmt;
- img.width = item.w; img.height = item.h;
- img.dataset.w = item.w;
- view.append(img);
- p.append(label, view);
- return p;
- }
-
- function render(list, target) {
- list.forEach(function (item) {
- var card = el('article', 'item' + (item.wide ? ' wide' : ''));
- var head = el('div', 'item-head');
- head.append(el('span', 'name', item.file), el('span', 'dims', item.w + ' × ' + item.h));
- var saved = Math.round((1 - item.jpg / item.png) * 100);
- head.append(el('span', 'pill good', 'JPG ' + saved + '% smaller'));
- if (item.misprint) head.append(el('span', 'pill warn', 'Do not use: reads "pomostcard"'));
- var cmp = el('div', 'compare');
- var a = panel('PNG', 'images/logos/png/' + item.file + '.png', item.png, item);
- var b = panel('JPG', 'images/logos/jpg/' + item.file + '.jpg', item.jpg, item);
- cmp.append(a, b);
- linkScroll(a.querySelector('.view'), b.querySelector('.view'));
- card.append(head, cmp);
- target.append(card);
- });
- }
-
- function linkScroll(x, y) {
- var lock = false;
- function sync(from, to) {
- from.addEventListener('scroll', function () {
- if (lock) return;
- lock = true;
- to.scrollLeft = from.scrollLeft; to.scrollTop = from.scrollTop;
- requestAnimationFrame(function () { lock = false; });
- });
- }
- sync(x, y); sync(y, x);
- }
-
- render(lockups, document.getElementById('lockups'));
- render(icons, document.getElementById('icons'));
-
- var all = lockups.concat(icons);
- var pngTotal = all.reduce(function (s, i) { return s + i.png; }, 0);
- var jpgTotal = all.reduce(function (s, i) { return s + i.jpg; }, 0);
- var totals = document.getElementById('totals');
- totals.innerHTML = '';
- [['All PNGs', pngTotal.toFixed(0) + ' KB'], ['All JPGs', jpgTotal.toFixed(0) + ' KB'],
- ['Saved', Math.round((1 - jpgTotal / pngTotal) * 100) + '%']].forEach(function (t) {
- var s = el('span', null, t[0] + ' ');
- s.append(el('b', null, t[1]));
- totals.append(s);
- });
-
- function setBg(bg) {
- document.body.setAttribute('data-bg', bg);
- document.querySelectorAll('#bg-seg button').forEach(function (b) { b.setAttribute('aria-pressed', String(b.dataset.bg === bg)); });
- try { localStorage.setItem('logo-bg', bg); } catch (e) {}
- }
- function setZoom(z) {
- document.body.setAttribute('data-zoom', z);
- document.querySelectorAll('#zoom-seg button').forEach(function (b) { b.setAttribute('aria-pressed', String(b.dataset.zoom === z)); });
- document.querySelectorAll('.view img').forEach(function (img) { img.style.width = (img.dataset.w * Number(z)) + 'px'; });
- if (z === '1') document.querySelectorAll('.view img').forEach(function (img) { img.style.width = ''; });
- try { localStorage.setItem('logo-zoom', z); } catch (e) {}
- }
- document.querySelectorAll('#bg-seg button').forEach(function (b) { b.addEventListener('click', function () { setBg(b.dataset.bg); }); });
- document.querySelectorAll('#zoom-seg button').forEach(function (b) { b.addEventListener('click', function () { setZoom(b.dataset.zoom); }); });
-
- var savedBg = 'light', savedZoom = '1';
- try { savedBg = localStorage.getItem('logo-bg') || 'light'; savedZoom = localStorage.getItem('logo-zoom') || '1'; } catch (e) {}
- setBg(savedBg);
- setZoom(savedZoom);
- })();
- </script>
|