landing: add product screenshots — hero shot, feature thumbnails, lightbox
Five PNGs at app/static/images/ (renamed from screenshot dumps): - dashboard.png — full dashboard hero shot, sits below the hero CTAs - news-feed.png — feature-card thumbnail: auto-tagged news feed - indicators-read.png — feature-card thumbnail: per-group AI commentary - strategic-log.png — feature-card thumbnail: hourly strategic log text - chat-with-log.png — "More views" gallery: ask follow-ups against a log Every screenshot is a <button class="shot"> with data-full + data-caption; click opens an HTML5 <dialog>-based lightbox. <dialog> handles focus trap, ESC-to-close, inert background; the backdrop click closes too. Images use loading="lazy" so the lightbox-only ones don't block first paint. CSS appended to cassandra.css: .shot, .shot-hero, .shots-grid, .shot__caption, and .shot-modal (+ ::backdrop). All colours pull from the existing palette vars so light and dark themes stay coherent. Total image weight: ~950 KB across all five — acceptable for a marketing landing page with lazy-loaded thumbnails.
This commit is contained in:
parent
13ea63be5c
commit
4ded3632e9
7 changed files with 226 additions and 0 deletions
|
|
@ -1724,3 +1724,150 @@ a.btn-secondary:hover { color: var(--accent); border-color: var(--accent); }
|
|||
vertical-align: middle;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Landing-page screenshots: hero shot, thumbnails inside feature cards, gallery
|
||||
strip, and a <dialog>-based lightbox. See app/templates/landing.html. */
|
||||
|
||||
/* All clickable screenshots are <button>s — reset the default chrome so they
|
||||
read as image cards, not form controls. */
|
||||
.shot {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background: transparent;
|
||||
border: 1px solid var(--border);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
cursor: zoom-in;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
transition: border-color 120ms ease, transform 120ms ease;
|
||||
position: relative;
|
||||
}
|
||||
.shot:hover,
|
||||
.shot:focus-visible {
|
||||
border-color: var(--accent);
|
||||
outline: none;
|
||||
}
|
||||
.shot:focus-visible {
|
||||
box-shadow: 0 0 0 2px var(--accent);
|
||||
}
|
||||
.shot img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Hero screenshot — sits just below the headline CTAs, full landing width. */
|
||||
.shot-hero {
|
||||
max-width: 960px;
|
||||
margin: 0 auto 56px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
.shot--hero .shot__zoom {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 12px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--bg);
|
||||
background: var(--accent);
|
||||
padding: 4px 9px;
|
||||
border-radius: 3px;
|
||||
opacity: 0.85;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Thumbnail tucked at the bottom of each feature card. */
|
||||
.feature-card__shot {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.feature-card__shot img {
|
||||
max-height: 200px;
|
||||
object-fit: cover;
|
||||
object-position: top left;
|
||||
}
|
||||
|
||||
/* "More views" strip — flex so we can drop in 2-3 extra shots later. */
|
||||
.shots-section {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.shots-grid {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
margin-top: 12px;
|
||||
}
|
||||
.shot__caption {
|
||||
padding: 10px 12px;
|
||||
font-size: 12.5px;
|
||||
line-height: 1.5;
|
||||
color: var(--muted);
|
||||
background: var(--surface);
|
||||
border-top: 1px solid var(--border);
|
||||
text-align: left;
|
||||
}
|
||||
.shot__caption strong {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
color: var(--text);
|
||||
margin-bottom: 2px;
|
||||
font-family: var(--font-mono);
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
/* Lightbox. <dialog> handles the modal mechanics (focus trap, ESC-to-close,
|
||||
inert background); we just style the surface. */
|
||||
.shot-modal {
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--text);
|
||||
max-width: min(96vw, 1400px);
|
||||
max-height: 94vh;
|
||||
padding: 0;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.shot-modal::backdrop {
|
||||
background: rgba(0, 0, 0, 0.78);
|
||||
}
|
||||
.shot-modal img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 80vh;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.shot-modal p {
|
||||
margin: 0;
|
||||
padding: 14px 22px 18px;
|
||||
font-size: 13.5px;
|
||||
line-height: 1.6;
|
||||
color: var(--muted);
|
||||
border-top: 1px solid var(--border);
|
||||
background: var(--surface-2);
|
||||
}
|
||||
.shot-modal__close {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 8px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
color: var(--text);
|
||||
font-size: 28px;
|
||||
line-height: 1;
|
||||
padding: 4px 10px;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
.shot-modal__close:hover,
|
||||
.shot-modal__close:focus-visible {
|
||||
color: var(--accent);
|
||||
outline: none;
|
||||
}
|
||||
|
|
|
|||
BIN
app/static/images/chat-with-log.png
Normal file
BIN
app/static/images/chat-with-log.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 243 KiB |
BIN
app/static/images/dashboard.png
Normal file
BIN
app/static/images/dashboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 145 KiB |
BIN
app/static/images/indicators-read.png
Normal file
BIN
app/static/images/indicators-read.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
BIN
app/static/images/news-feed.png
Normal file
BIN
app/static/images/news-feed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 252 KiB |
BIN
app/static/images/strategic-log.png
Normal file
BIN
app/static/images/strategic-log.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
|
|
@ -25,6 +25,17 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section class="shot-hero">
|
||||
<button class="shot shot--hero"
|
||||
data-full="{{ url_for('static', path='/images/dashboard.png') }}"
|
||||
data-alt="Read the Markets dashboard"
|
||||
data-caption="The dashboard. An aggregate cross-asset read at the top, hand-picked indicator groups underneath. Reading level toggle (Novice / Intermediate) flips every AI-generated panel between plain-English and terse-pro framing.">
|
||||
<img src="{{ url_for('static', path='/images/dashboard.png') }}"
|
||||
alt="Dashboard preview" loading="lazy">
|
||||
<span class="shot__zoom" aria-hidden="true">Click to enlarge</span>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="feature-grid">
|
||||
<div class="feature-card">
|
||||
<div class="feature-card__tag">News, aggregated</div>
|
||||
|
|
@ -36,6 +47,13 @@
|
|||
stuff is easy to find. Ingestion follows the trading calendar —
|
||||
off-hours stay quiet.
|
||||
</p>
|
||||
<button class="shot feature-card__shot"
|
||||
data-full="{{ url_for('static', path='/images/news-feed.png') }}"
|
||||
data-alt="News feed with auto-tagged headlines"
|
||||
data-caption="The news feed. Each headline carries one or more theme tags (rates, AI, energy, geopolitics, …) so you can keep the threads you care about and mute the ones you don't. Click a tag to include; shift-click to exclude.">
|
||||
<img src="{{ url_for('static', path='/images/news-feed.png') }}"
|
||||
alt="News feed thumbnail" loading="lazy">
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
|
|
@ -47,6 +65,13 @@
|
|||
explains what the move <em>means</em>, not what it was. Anchored
|
||||
in earnings, policy, valuation — not chart patterns.
|
||||
</p>
|
||||
<button class="shot feature-card__shot"
|
||||
data-full="{{ url_for('static', path='/images/indicators-read.png') }}"
|
||||
data-alt="Indicators panel with AI commentary"
|
||||
data-caption="The indicators panel. Tabs across asset classes (equity, rates, commodities, FX, bonds, …); each tab carries a one-paragraph 'read' written by the model on top of the live prices. The numbers anchor the prose so the commentary is checkable, not floating.">
|
||||
<img src="{{ url_for('static', path='/images/indicators-read.png') }}"
|
||||
alt="Indicators panel thumbnail" loading="lazy">
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
|
|
@ -61,6 +86,30 @@
|
|||
intermediate. This is editorial commentary on public data —
|
||||
not a forecast and not advice on any investment decision.
|
||||
</p>
|
||||
<button class="shot feature-card__shot"
|
||||
data-full="{{ url_for('static', path='/images/strategic-log.png') }}"
|
||||
data-alt="Strategic log — the hourly AI read"
|
||||
data-caption="The strategic log. The model writes a fresh interpretation each hour, taking yesterday's draft as context so it updates rather than starts over. Sections are typed: date header, TL;DR, what moved, what to watch, system temperature.">
|
||||
<img src="{{ url_for('static', path='/images/strategic-log.png') }}"
|
||||
alt="Strategic log thumbnail" loading="lazy">
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="public-section shots-section">
|
||||
<h2 class="public-section__head">More views</h2>
|
||||
<div class="shots-grid">
|
||||
<button class="shot"
|
||||
data-full="{{ url_for('static', path='/images/chat-with-log.png') }}"
|
||||
data-alt="Ask follow-up questions against any past log"
|
||||
data-caption="Ask follow-up questions against any past log. The chat panel inherits the log's full context, so you can pull on a thread without re-pasting headlines or re-explaining the setup.">
|
||||
<img src="{{ url_for('static', path='/images/chat-with-log.png') }}"
|
||||
alt="Chat-with-log thumbnail" loading="lazy">
|
||||
<div class="shot__caption">
|
||||
<strong>Ask anything about a log</strong>
|
||||
<span>Conversational follow-ups with the day's context loaded.</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -100,4 +149,34 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<dialog id="shot-modal" class="shot-modal" aria-label="Screenshot preview">
|
||||
<button class="shot-modal__close" type="button" aria-label="Close">×</button>
|
||||
<img id="shot-modal__img" alt="">
|
||||
<p id="shot-modal__caption"></p>
|
||||
</dialog>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var dlg = document.getElementById('shot-modal');
|
||||
var img = document.getElementById('shot-modal__img');
|
||||
var cap = document.getElementById('shot-modal__caption');
|
||||
if (!dlg || !dlg.showModal) return; // gracefully skip on ancient browsers
|
||||
document.querySelectorAll('.shot').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
img.src = btn.dataset.full;
|
||||
img.alt = btn.dataset.alt || '';
|
||||
cap.textContent = btn.dataset.caption || '';
|
||||
dlg.showModal();
|
||||
});
|
||||
});
|
||||
// Backdrop click closes; clicking the image itself does not.
|
||||
dlg.addEventListener('click', function (e) {
|
||||
if (e.target === dlg) dlg.close();
|
||||
});
|
||||
dlg.querySelector('.shot-modal__close').addEventListener('click', function () {
|
||||
dlg.close();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue