Files
client/www/css/client.css
Laan Tungir a42edcf6d6 Feed upgrade Phases 3-5: zap capability indicators, rail selector, balance checks
Phase 3 — Zap Capability Indicators:
- Added resolveZapCapabilities() to zaps.mjs with 5-min TTL cache
- Checks lud16 (from profile cache) for Lightning capability
- Checks kind 10019 (via walletFetchMintList) for nutzap capability
- Computes shared mints between sender and recipient
- Added capability badges (🥜/) to zap button in post-interactions.mjs
- Badges use var(--accent-color) for available, var(--muted-color) for unavailable
- Added proactive kind 10019 batch fetch for followed users in ndk-worker.js
- New IDB store ndk-nutzap-mintlists for persistent caching (6h TTL)
- Non-blocking: badges appear after async resolution

Phase 4 — Zap Rail Selector:
- Updated promptZapDetails with rail toggle (🥜 Nutzap /  Lightning)
- Shows Cashu balance and insufficient balance warning
- Shows shared mint info when nutzap selected
- Default rail: nutzap for <1000 sats, Lightning for >=1000 sats
- Updated handleZapClick to resolve capabilities and respect user's rail choice
- Added zap rail toggle CSS to client.css (all CSS variables)
- Wired walletGetBalance through post-interactions2.mjs and post-feed.html

Phase 5 — Balance Check and Error Handling:
- Pre-flight balance check before sending (hard stop if insufficient)
- Barely-sufficient balance confirmation dialog
- Friendly error messages for melt/swap/timeout/insufficient failures
- Post-zap balance refresh via ndkWalletBalance event

Review fix: threaded walletGetMints through post-interactions2.mjs and post-feed.html
so resolveZapCapabilities can compute shared mints correctly
2026-06-25 20:48:38 -04:00

1621 lines
35 KiB
CSS

/* ************************************************************************* */
/* CLIENT CSS */
/* ************************************************************************* */
/* CSS SETTINGS SHARED ACROSS ALL CLIENT PAGES. */
/*
* =========================================================================
* CSS PLACEMENT RULES (FOR AI AGENTS AND DEVELOPERS)
* =========================================================================
*
* This project uses a two-tier CSS architecture:
*
* 1. client.css — Global shared styles (this file)
* 2. <style> — Page-specific styles (inline in each HTML file)
*
* -------------------------------------------------------------------------
* WHAT GOES IN client.css (this file):
* -------------------------------------------------------------------------
* - CSS custom properties / variables (:root, dark-mode overrides)
* - Font declarations (@font-face)
* - Global reset (* selector, html, body, a)
* - Layout shell: #divHeader, #divBody, #divFooter, #divSideNav,
* #divVersionBar, #divRelaySection and their direct children
* - Header button styles (.divHeaderButtons, .svgHeaderButtons)
* - Footer box styles (.divFooterBox)
* - Utility classes (.clsHidden, .clsVisible, .clsFullScreenDiv)
* - Reusable component classes used on multiple pages
*
* -------------------------------------------------------------------------
* WHAT GOES IN PAGE <style> BLOCKS:
* -------------------------------------------------------------------------
* - Styles for elements unique to that page (e.g., #taNote, #tblTags)
* - Layout overrides for #divBody ONLY via these allowed properties:
* flex-direction, flex-wrap, align-items, justify-content,
* align-content, gap
* Always use !important when overriding #divBody from page styles.
* - Page-specific element sizing, positioning, and spacing
*
* -------------------------------------------------------------------------
* RULES:
* -------------------------------------------------------------------------
*
* 1. NEVER hardcode colors in page <style> blocks.
* Always use CSS variables: var(--primary-color), var(--secondary-color),
* var(--accent-color), var(--muted-color), var(--background-color).
*
* 2. NEVER redefine layout shell IDs (#divHeader, #divFooter, #divSideNav,
* #divVersionBar, #divRelaySection) in page <style> blocks.
* These are global and must look the same on every page.
*
* 3. NEVER use element-type selectors (div, table, img, iframe, textarea)
* in client.css. Use IDs or classes instead.
*
* 4. When overriding #divBody layout in a page <style>, override ALL
* flex properties together to avoid inheriting conflicting values:
* #divBody {
* flex-direction: column !important;
* flex-wrap: nowrap !important;
* align-items: stretch !important;
* justify-content: flex-start !important;
* align-content: flex-start !important;
* }
*
* 5. Use .clsHidden and .clsVisible from client.css for show/hide.
* Do NOT redefine these in page <style> blocks.
*
* 6. Buttons, inputs, and interactive elements should use CSS variables
* for colors so they automatically adapt to dark/light mode.
*
* 7. Font family should always be var(--font-family) unless a specific
* element needs var(--font-mono) or pageKanji.
*
* 8. If a style is used on 2+ pages, move it to client.css.
* If a style is used on only 1 page, keep it in that page's <style>.
*
* 9. The default #divBody layout is flex-direction: row with wrap.
* Pages that need vertical stacking MUST override to column/nowrap.
*
* 10. All spacing should use consistent values: 5px, 10px, 15px, 20px, 40px.
* Do not use arbitrary pixel values.
*
* =========================================================================
*/
@import url('./sidenav-sections.css');
@font-face {
font-family: pageMono;
src: url(./NotoMono-Regular.ttf);
/* src: url(./courier-new.ttf); */
/* src: url(./Calcula.ttf); */
/* src: url(./IBMPlexMono-Thin.ttf); */
}
@font-face {
font-family: pageKanji;
src: url(./GenShin.ttf);
/* src: url(./Gisshiri.ttf); */
}
:root {
/* Core Variables */
--font-family: "pageMono", Courier, monospace;
--primary-color: #000000;
--secondary-color: #ffffff;
--accent-color: #ff0000;
--muted-color: #dddddd;
--border-color: var(--muted-color);
--border-radius: 5px;
--border-width: 1px;
--border-width2: 2px;
--border-width3: 3px;
/* Image Effects */
--image-grayscale: 100%;
--image-grayscale-hover: 20%;
/* Derived Variables */
--color: var(--primary-color);
--background-color: var(--secondary-color);
/* Button Values */
--button-color: var(--primary-color);
--button-background-color: var(--secondary-color);
--button-hover-color: var(--accent-color);
--button-click-color: var(--accent-color);
--button-click-text-color: var(--secondary-color);
--button-border-color: var(--primary-color);
--button-border-radius: var(--border-radius);
--button-border-width: var(--border-width);
/* Avatar Tokens */
--avatar-size-sm: 20px;
--avatar-size-md: 32px;
--avatar-size-lg: 52px;
--avatar-size-xl: 80px;
--avatar-radius: var(--border-radius);
--border: var(--border-width) solid var(--border-color);
--header-border: var(--border-width) solid var(--primary-color);
/* Layout Variables */
--header-height: 2vh;
--header-min-height: 60px;
--footer-height: 2vh;
--footer-min-height: 20px;
color-scheme: light;
}
/* Dark Mode Overrides */
html.dark-mode,
body.dark-mode {
--primary-color: #ffffff;
--secondary-color: #000000;
--accent-color: #ff0000;
--muted-color: #777777;
--border-color: var(--muted-color);
}
html.dark-mode {
color-scheme: dark;
}
* {
font-family: var(--font-family);
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
html,
body {
color: var(--color);
background-color: var(--background-color);
margin: 0px;
height: 100%;
}
html {
transition: background-color 0.2s ease, color 0.2s ease;
}
a {
text-decoration: none;
transition: 0.2s;
margin: 0px;
color: var(--primary-color);
}
a:visited {
color: var(--primary-color);
cursor: pointer;
}
a:hover {
color: var(--button-hover-color);
cursor: pointer;
}
/* Nostr entity rendering (shared) */
.nostr-mention {
display: inline-flex;
align-items: center;
gap: 5px;
color: var(--accent-color);
text-decoration: underline;
}
.nostr-mention-name {
color: var(--accent-color);
}
.nostr-link {
color: var(--accent-color);
text-decoration: underline;
}
.nostr-embed {
margin: 10px 0;
padding: 10px;
border: 1px solid var(--muted-color);
border-radius: var(--border-radius);
background: var(--secondary-color);
color: var(--primary-color);
}
.nostr-embed-label {
font-size: 80%;
color: var(--muted-color);
margin-bottom: 5px;
}
.nostr-embed-label-prefix {
color: var(--muted-color);
}
.nostr-embed-author-link {
display: inline-flex;
align-items: center;
gap: 5px;
color: var(--accent-color);
text-decoration: none;
}
.nostr-embed-author-link:hover {
color: var(--button-hover-color);
text-decoration: underline;
}
.nostr-embed-author-avatar {
width: 16px;
height: 16px;
border-radius: 4px;
object-fit: cover;
flex-shrink: 0;
border: 1px solid var(--muted-color);
}
.nostr-embed-author-name {
color: inherit;
}
.nostr-embed-content {
white-space: pre-wrap;
word-break: break-word;
font-size: 95%;
}
.nostr-embed-thumb-link {
display: block;
margin-bottom: 6px;
}
.nostr-embed-thumb {
display: block;
width: 100%;
max-height: 240px;
object-fit: cover;
border-radius: 8px;
border: 1px solid var(--muted-color);
}
.nostr-embed-thumb-avatar {
width: 40px;
height: 40px;
max-height: 40px;
border-radius: 999px;
object-fit: cover;
border: 1px solid var(--muted-color);
}
.nostr-embed-preview-text {
display: block;
color: var(--primary-color);
text-decoration: none;
white-space: pre-wrap;
word-break: break-word;
}
a.nostr-embed-preview-text:hover {
color: var(--button-hover-color);
text-decoration: underline;
}
.nostr-profile-inline {
display: inline-flex;
vertical-align: middle;
margin: 2px 0;
}
.nostr-profile-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 2px 6px;
border: 1px solid var(--muted-color);
border-radius: 8px;
background: var(--secondary-color);
color: var(--accent-color);
text-decoration: none;
}
.nostr-profile-link:hover {
color: var(--button-hover-color);
border-color: var(--button-hover-color);
}
.nostr-profile-avatar {
width: 18px;
height: 18px;
border-radius: 4px;
object-fit: cover;
flex-shrink: 0;
}
.nostr-profile-name {
color: inherit;
font-size: 90%;
line-height: 1;
}
/* ************************************************************************* */
/* MAIN LAYOUT */
/* ************************************************************************* */
#divHeader {
position: fixed;
top: 0px;
left: 0px;
right: 0px;
height: var(--header-height);
min-height: var(--header-min-height);
color: var(--primary-color);
background-color: var(--secondary-color);
z-index: 2;
/* border-bottom: 3px solid var(--primary-color); */
}
#divBody {
position: relative;
top: max(var(--header-height), var(--header-min-height));
background-color: var(--background-color);
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
align-content: space-around;
width: 100%;
height: 90%;
padding: 20px;
overflow-y: auto;
}
#divFooter {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
position: fixed;
bottom: 0px;
left: 0px;
right: 0px;
color: var(--primary-color);
background-color: var(--secondary-color);
height: var(--footer-height);
min-height: var(--footer-min-height);
z-index: 2;
border-top: 3px solid var(--primary-color);
}
/* ************************************************************************* */
/* HEADER LAYOUT */
/* ************************************************************************* */
#divHeaderFlexLeft {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
}
#divHeaderFlexCenter {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
}
#divHeaderFlexRight {
display: flex;
flex-direction: row-reverse;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
/* border:3px solid blue; */
}
/* ************************************************************************* */
/* SIDENAV LAYOUT */
/* ************************************************************************* */
#divSideNav {
height: 100%;
width: 0;
position: fixed;
z-index: -1;
top: 0;
left: 0;
color: var(--primary-color);
background-color: var(--secondary-color);
/* overflow-y: hidden; */
overflow-x: hidden;
transition: 0.5s;
border-right: 3px solid var(--primary-color);
display: flex;
flex-direction: column;
}
#divSideNavHeader {
height: var(--header-height);
min-height: var(--header-min-height);
color: var(--primary-color);
background-color: var(--secondary-color);
z-index: 3;
border-bottom: 3px solid var(--primary-color);
}
#divSideNavBody {
padding: 20px;
background-color: var(--secondary-color);
flex: 1;
overflow-y: auto;
}
.blossomServerDropTarget {
transition: color 0.2s, border-color 0.2s, outline-color 0.2s;
padding: 2px 4px;
border-radius: var(--border-radius);
}
.blossomServerDropTarget.dragover {
color: var(--accent-color) !important;
font-weight: bold !important;
outline: 1px dashed var(--accent-color);
outline-offset: 2px;
}
.blossomServerGrip {
cursor: grab;
user-select: none;
opacity: 0.6;
transition: opacity 0.2s, color 0.2s;
}
.blossomServerGrip:hover {
opacity: 1;
color: var(--accent-color) !important;
}
.blossomServerGrip:active {
cursor: grabbing;
}
.blossomServerDragging {
opacity: 0.4;
}
.blossomServerDropZone {
border-top: 2px solid var(--accent-color) !important;
}
#divVersionBar {
flex-shrink: 0;
height: max(var(--header-height), var(--header-min-height));
min-height: var(--header-min-height);
background-color: var(--secondary-color);
border-top: 3px solid var(--primary-color);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
box-sizing: border-box;
}
#versionDisplay {
font-size: 14px;
color: var(--primary-color);
font-weight: 500;
}
#divVersionBarButtons {
display: flex;
gap: 10px;
align-items: center;
}
#themeToggleButton,
#logoutButton,
#homeButton,
#commentsToggleButton {
background: none;
border: none;
cursor: pointer;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s ease, color 0.2s;
width: 24px;
height: 24px;
}
#themeToggleHamburgerContainer,
#logoutHamburgerContainer,
#homeHamburgerContainer {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
#themeToggleHamburgerContainer svg,
#logoutHamburgerContainer svg,
#homeHamburgerContainer svg {
width: 24px;
height: 24px;
}
#commentsToggleButton {
font-family: var(--font-family);
font-size: inherit;
color: var(--button-color);
background-color: var(--button-background-color);
border: 1px solid var(--button-border-color);
border-radius: var(--button-border-radius);
padding: 4px 8px;
cursor: pointer;
transition: opacity 0.2s, color 0.2s, border-color 0.2s;
margin: 0;
opacity: 1;
white-space: nowrap;
width: auto;
height: auto;
}
#commentsToggleButton:hover {
color: var(--button-hover-color);
border-color: var(--button-hover-color);
}
/* Global Button Class */
.btn {
font-family: var(--font-family);
color: var(--button-color);
background-color: var(--button-background-color);
border: var(--button-border-width) solid var(--button-border-color);
border-radius: var(--button-border-radius);
cursor: pointer;
transition: border-color 0.2s, background-color 0.2s, color 0.2s;
padding: 8px 16px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
font-size: 14px;
font-weight: bold;
line-height: 1;
}
.btn:hover {
border-color: var(--button-hover-color);
/* color: var(--button-hover-color); */
}
.btn:active {
background-color: var(--button-click-color);
color: var(--button-click-text-color);
border-color: var(--button-border-color);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
#commentsToggleButton.dimmed {
opacity: 0.5;
}
#commentsToggleButton.visible {
color: var(--primary-color);
border-color: var(--primary-color);
}
#divCommentsSection {
padding: 10px 20px;
border-top: 1px solid var(--border-color);
}
#divFooterLeft,
#divFooterCenter,
#divFooterRight,
#divFooterBalance {
display: flex;
gap: 5px;
}
#divFooterLeft,
#divFooterCenter,
#divFooterRight {
flex: 1 1 0;
min-width: 0;
}
#divFooterCenter {
justify-content: center;
align-items: center;
}
#divFooterRight {
border-right: none;
}
#divFooterBalance {
flex: 0 0 auto;
width: auto;
min-width: fit-content;
white-space: nowrap;
border-left: 3px solid var(--primary-color);
border-right: none;
justify-content: center;
align-items: center;
}
/* ************************************************************************* */
/* RIGHTNAV LAYOUT */
/* ************************************************************************* */
#divRightNav {
height: 100%;
width: 0;
position: fixed;
z-index: -1;
top: 0;
right: 0;
color: var(--primary-color);
background-color: var(--secondary-color);
overflow-y: hidden;
overflow-x: hidden;
transition: 0.4s;
border-left: 3px solid var(--primary-color);
}
#divRightNavBody {
padding-top: 20px;
background-color: var(--secondary-color);
overflow-y: auto;
/* font-size: 5vw; */
}
/* ************************************************************************* */
/* FOOTER LAYOUT */
/* ************************************************************************* */
.divFooterBox {
font-family: var(--font-family);
font-size: 50%;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
align-content: stretch;
border-right: 3px solid var(--primary-color);
padding-left: 10px;
padding-right: 10px;
}
/* ************************************************************************* */
/* ************************************************************************* */
/* SVG HEADER BUTTONS */
/* ************************************************************************* */
/* ************************************************************************* */
.divHeaderButtons {
padding-left: 0px;
padding-right: 20px;
display: flex;
align-items: center;
height: max(var(--header-height), var(--header-min-height));
z-index: 3;
/* border:1px solid red; */
}
.divHeaderAvatarLink {
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
margin-right: 20px;
}
.divHeaderAvatar {
width: 50px;
height: 50px;
border-radius: var(--border-radius);
border: var(--border-width) solid var(--primary-color);
background-color: transparent;
object-fit: cover;
cursor: pointer;
filter: grayscale(var(--image-grayscale));
transition: filter 0.2s;
}
.divHeaderAvatar.is-placeholder {
background-color: transparent;
}
.divHeaderAvatar:hover {
filter: grayscale(var(--image-grayscale-hover));
}
.divHeaderLoginBtn {
width: 50px;
height: 50px;
border-radius: var(--border-radius);
border: var(--border-width) solid var(--primary-color);
background-color: transparent;
color: var(--primary-color);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
padding: 0;
font-size: 24px;
line-height: 1;
filter: grayscale(var(--image-grayscale));
transition: filter 0.2s;
}
.divHeaderLoginBtn:hover {
filter: grayscale(var(--image-grayscale-hover));
}
#divSvgHam {
position: fixed;
top: 0;
left: 0;
height: 55px;
/* Sets size of hamburger menu button */
z-index: 10;
width: auto;
}
#divSvgHam svg {
z-index: 10;
position: relative;
}
.divHeaderText {
padding-top: 10px;
color: var(--primary-color);
font-size: max(var(--header-height), var(--header-min-height));
font-weight: bold;
z-index: 3;
}
.svgHeaderButtons {
fill: none;
stroke: var(--button-color);
stroke-width: 1.98;
stroke-linecap: round;
stroke-linejoin: round;
transition: 0.2s;
height: 100%;
z-index: 3;
}
.svgHeaderButtonsUnsellected {
fill: none;
stroke: var(--muted-color);
stroke-width: 1.98;
stroke-linecap: round;
stroke-linejoin: round;
transition: 0.2s;
height: 100%;
z-index: 3;
}
.divHeaderButtons:hover {
stroke: var(--button-hover-color);
cursor: pointer;
}
.svgHeaderButtons:hover path {
stroke: var(--button-hover-color);
cursor: pointer;
}
.svgHeaderButtons:hover circle {
stroke: var(--button-hover-color);
cursor: pointer;
}
.svgHeaderButtons:hover line {
stroke: var(--button-hover-color);
cursor: pointer;
}
.svgHeaderButtons:hover polygon {
stroke: var(--button-hover-color);
cursor: pointer;
}
#svgCarrotPath {
transition: 0.4s;
}
/* ************************************************************************* */
/* ICONS */
/* ************************************************************************* */
.svgIcon {
width: 1em;
stroke: var(--primary-color);
transition: 0.2s;
z-index: 1;
margin-right: 10px;
}
.svgIcon:hover {
cursor: pointer;
stroke: var(--accent-color);
}
.svgIconMedium {
width: 2em;
stroke: var(--primary-color);
transition: 0.2s;
z-index: 1;
margin-right: 10px;
}
.svgIconMedium:hover {
cursor: pointer;
stroke: var(--accent-color);
}
.svgIconDim {
stroke: var(--muted-color);
}
/* ************************************************************************* */
/* GENERAL */
/* ************************************************************************* */
.clsHidden {
display: none;
}
.clsVisible {
display: block;
}
.clsFullScreenDiv {
position: fixed;
top: var(--header-height);
left: 0;
bottom: var(--footer-height);
right: 0;
overflow: hidden;
}
/* ************************************************************************* */
/* POST CARDS */
/* ************************************************************************* */
.divPostItem {
padding: 12px 12px 0px 12px;
border: 1px solid var(--primary-color);
border-radius: 10px;
margin-bottom: 15px;
background: var(--secondary-color);
color: var(--primary-color);
display: flex;
flex-direction: column;
}
.divPostHeader,
.divPostContent {
filter: grayscale(var(--image-grayscale));
transition: filter 0.2s;
}
.divPostItem:hover .divPostHeader,
.divPostItem:hover .divPostContent {
filter: grayscale(var(--image-grayscale-hover));
}
.divPostItem.is-read {
border-color: var(--muted-color);
}
.divPostItem.is-unread {
border-color: var(--primary-color);
}
.divPostContent {
font-size: 100%;
color: var(--primary-color);
white-space: pre-wrap;
margin-bottom: 10px;
word-wrap: break-word;
}
.divPostContent a {
color: var(--accent-color);
text-decoration: underline;
}
.divPostContent img:not(.nostr-embed-author-avatar):not(.nostr-embed-thumb-avatar) {
border-radius: 10px;
width: 100%;
height: auto;
display: block;
margin: 10px 0;
}
.divPostContent .post-video-embed,
.divPostContent video {
border-radius: 10px;
width: 100%;
max-width: 100%;
height: auto;
display: block;
margin: 10px 0;
background: #000; /* Intentional black background for embedded video content */
}
.divPostFooterRow {
display: flex;
align-items: center;
justify-content: space-between;
border-top: none;
width: 100%;
min-width: 0;
overflow: hidden;
gap: 0;
}
.divPostTime {
font-size: 14px;
color: var(--muted-color);
white-space: nowrap;
min-width: 0;
margin-left: auto;
text-align: right;
overflow: hidden;
text-overflow: ellipsis;
justify-content: flex-end;
}
/* ************************************************************************* */
/* POST INTERACTIONS */
/* ************************************************************************* */
/* Interaction bar container - horizontal row of action buttons */
.divPostInteractions {
display: flex !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
align-items: center !important;
justify-content: flex-start !important;
flex: 1 1 auto;
gap: 10px;
padding: 10px 0;
margin-top: 0;
border-top: 1px solid var(--border-color);
}
.divPostMidControls {
display: flex;
flex: 1 1 auto;
justify-content: space-evenly;
align-items: center;
min-width: 0;
gap: 0;
}
.divPostInteractions .interaction-item.zap {
flex: 0 0 auto;
}
.nutzap-count-display {
display: none;
align-items: center;
gap: 4px;
padding: 2px 4px;
color: var(--muted-color);
user-select: none;
pointer-events: none;
min-width: 0;
}
.nutzap-count-display.has-count {
display: inline-flex;
}
.nutzap-count-display .nutzap-emoji {
font-size: 12px;
line-height: 1;
}
.nutzap-count-display .nutzap-count-value {
font-size: 14px;
color: var(--primary-color);
min-width: 0;
text-align: left;
}
.divPostMidControls .interaction-item {
flex: 1 1 0;
justify-content: center;
text-align: center;
min-width: 0;
}
/* Individual interaction item (like, comment, repost, zap) */
.interaction-item {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 6px;
cursor: pointer;
padding: 4px 6px;
border-radius: 5px;
transition: background-color 0.2s;
color: var(--muted-color);
}
.interaction-item:hover {
color: var(--accent-color);
}
.interaction-item:hover .interaction-icon {
color: var(--accent-color);
}
.interaction-item.active {
color: var(--muted-color);
}
.interaction-item.active .interaction-icon {
color: var(--muted-color);
font-weight: normal;
}
/* Icon container */
.interaction-icon-container {
display: flex;
align-items: center;
justify-content: center;
width: auto;
min-width: 0;
height: 20px;
}
/* Letter-based interaction icons */
.interaction-icon {
font-family: var(--font-family);
font-size: 13px;
color: currentColor;
transition: color 0.2s;
user-select: none;
}
.interaction-icon.active {
color: var(--muted-color);
font-weight: normal;
}
.interaction-item.zap.zap-pending {
color: var(--muted-color);
}
.interaction-item.zap.zap-pending .interaction-icon,
.interaction-item.zap.zap-pending .interaction-icon.active,
.interaction-item.zap.zap-pending .interaction-count {
color: var(--muted-color) !important;
transition: color 240ms linear !important;
}
.interaction-item.zap.zap-pending.zap-pending-accent .interaction-icon,
.interaction-item.zap.zap-pending.zap-pending-accent .interaction-icon.active,
.interaction-item.zap.zap-pending.zap-pending-accent .interaction-count {
color: var(--accent-color) !important;
}
.interaction-item.zap.zap-success,
.interaction-item.zap.zap-success .interaction-icon,
.interaction-item.zap.zap-success .interaction-icon.active,
.interaction-item.zap.zap-success .interaction-count {
color: var(--accent-color) !important;
}
.interaction-item.zap .zap-user-amount {
color: var(--accent-color);
}
.interaction-item.zap .zap-total-amount {
color: var(--primary-color);
}
/* Count display */
.interaction-count {
font-size: 14px;
min-width: 20px;
text-align: left;
}
/* ************************************************************************* */
/* COMMENT THREADS */
/* ************************************************************************* */
/* Comment thread container */
.divCommentThread {
margin-top: 10px;
padding-left: 15px;
animation: slideDown 0.3s ease-out;
}
.divCommentThread.collapsed {
display: none;
}
.divCommentThread.hidden {
display: none !important;
}
@keyframes slideDown {
from {
opacity: 0;
max-height: 0;
}
to {
opacity: 1;
max-height: 1000px;
}
}
/* Comments list */
.divCommentsList {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 15px;
}
.no-comments {
color: var(--muted-color);
font-size: 14px;
font-style: italic;
padding: 10px 0;
}
/* Reply input box */
.divReplyBox {
display: flex;
flex-direction: column;
gap: 10px;
padding: 10px;
background: var(--secondary-color);
border: 1px solid var(--border-color);
border-radius: 5px;
}
/* Compact footer row for comments */
.divPostFooterRow.compact {
padding: 5px 0;
margin-top: 5px;
}
.divPostFooterRow.compact .divPostInteractions {
gap: 10px;
padding: 0;
margin-top: 0;
}
.divPostFooterRow.compact .interaction-item {
padding: 3px;
font-size: 12px;
}
.divPostFooterRow.compact .interaction-icon {
font-size: 11px;
}
.divPostFooterRow.compact .interaction-count {
font-size: 12px;
min-width: 16px;
}
.divPostFooterRow.compact .nutzap-count-display {
gap: 3px;
}
.divPostFooterRow.compact .nutzap-count-display .nutzap-emoji {
font-size: 11px;
}
.divPostFooterRow.compact .nutzap-count-display .nutzap-count-value {
font-size: 12px;
}
.divPostFooterRow.compact .divPostTime {
font-size: 12px;
}
.divPostFooterRow.compact .nutzap-count-display {
gap: 3px;
}
.divPostFooterRow.compact .nutzap-count-display .nutzap-emoji {
font-size: 11px;
}
.divPostFooterRow.compact .nutzap-count-display .nutzap-count-value {
font-size: 12px;
}
/* ************************************************************************* */
/* ZAP SELECTOR */
/* ************************************************************************* */
.zap-selector-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 16px;
}
.zap-selector {
width: min(420px, 100%);
background: var(--secondary-color);
color: var(--primary-color);
border: 1px solid var(--border-color);
border-radius: 10px;
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.25);
padding: 14px;
display: flex;
flex-direction: column;
gap: 10px;
}
.zap-selector-title {
font-family: var(--font-family);
font-size: 16px;
font-weight: 600;
}
.zap-selector-presets {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 6px;
}
.zap-preset,
.zap-cancel,
.zap-save-default,
.zap-send {
border: 1px solid var(--border-color);
border-radius: 8px;
background: var(--background-color);
color: var(--primary-color);
font-family: var(--font-family);
font-size: 13px;
padding: 8px 10px;
cursor: pointer;
}
.zap-preset.active {
border-color: var(--accent-color);
color: var(--accent-color);
}
.zap-selector-label {
display: flex;
flex-direction: column;
gap: 6px;
font-size: 13px;
color: var(--muted-color);
}
.zap-selector-amount,
.zap-selector-comment {
border: 1px solid var(--border-color);
border-radius: 8px;
background: var(--background-color);
color: var(--primary-color);
font-family: var(--font-family);
font-size: 14px;
padding: 8px 10px;
outline: none;
}
.zap-selector-amount:focus,
.zap-selector-comment:focus {
border-color: var(--accent-color);
}
.zap-selector-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.zap-send {
border-color: var(--primary-color);
background: var(--primary-color);
color: var(--secondary-color);
}
.zap-save-default {
border-style: dashed;
color: var(--accent-color);
}
/* Zap rail selector (Phase 4 — nutzap vs Lightning) */
.zap-rail-toggle {
display: flex;
gap: 6px;
}
.zap-rail-option {
flex: 1;
border: 1px solid var(--border-color);
border-radius: 8px;
background: var(--background-color);
color: var(--muted-color);
font-family: var(--font-family);
font-size: 13px;
padding: 8px 10px;
cursor: pointer;
text-align: center;
}
.zap-rail-option.active {
border-color: var(--accent-color);
color: var(--accent-color);
}
.zap-rail-single {
display: block;
border: 1px solid var(--accent-color);
border-radius: 8px;
background: var(--background-color);
color: var(--accent-color);
font-family: var(--font-family);
font-size: 13px;
padding: 8px 10px;
text-align: center;
}
.zap-selector-balance {
font-size: 12px;
color: var(--muted-color);
}
.zap-selector-warning {
font-size: 12px;
color: var(--accent-color);
display: none;
}
.zap-selector-mint-info {
font-size: 12px;
color: var(--muted-color);
}
.zap-selector-error {
font-size: 13px;
color: var(--accent-color);
}
.zap-send:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* ************************************************************************* */
/* AUTHOR HEADER */
/* ************************************************************************* */
/* Author header row (profile pic + name + menu button) */
.divPostHeader {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 10px;
position: relative;
z-index: 30;
}
.divPostHeaderMain {
display: flex;
align-items: center;
min-width: 0;
flex: 1 1 auto;
}
.divPostProfileLink {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
text-decoration: none;
color: inherit;
cursor: pointer;
}
/* Avatar Utilities */
.avatar {
width: var(--avatar-size-md);
height: var(--avatar-size-md);
object-fit: cover;
}
.avatar--sm {
width: var(--avatar-size-sm);
height: var(--avatar-size-sm);
}
.avatar--md {
width: var(--avatar-size-md);
height: var(--avatar-size-md);
}
.avatar--lg {
width: var(--avatar-size-lg);
height: var(--avatar-size-lg);
}
.avatar--xl {
width: var(--avatar-size-xl);
height: var(--avatar-size-xl);
}
.avatar--square {
border-radius: var(--avatar-radius);
}
.avatar--round {
border-radius: 999px;
}
/* Small square profile picture */
.divPostAvatar {
width: var(--avatar-size-md);
height: var(--avatar-size-md);
border-radius: var(--avatar-radius);
object-fit: cover;
filter: grayscale(var(--image-grayscale));
transition: filter 0.2s;
}
.divPostAvatar:hover {
filter: grayscale(var(--image-grayscale-hover));
}
/* Author display name */
.divPostAuthorName {
font-family: var(--font-family);
font-size: 14px;
color: var(--muted-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Legacy post menu styles retained as fallback while post cards now use dot-menu.css */
.divPostMenuWrap {
position: relative;
flex: 0 0 auto;
z-index: 40;
}
.divPostMenuButton {
width: var(--avatar-size-md);
height: var(--avatar-size-md);
border-radius: var(--avatar-radius);
border: 1px solid var(--muted-color);
background: var(--secondary-color);
color: var(--muted-color);
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--font-family);
font-size: 22px;
line-height: 1;
cursor: pointer;
padding: 0;
}
.divPostMenuButton:hover {
color: var(--accent-color);
border-color: var(--accent-color);
}
.divPostMenuDropdown {
position: absolute;
top: calc(100% + 5px);
right: 0;
z-index: 200;
display: none;
flex-direction: column;
min-width: 165px;
padding: 5px;
border: 1px solid var(--muted-color);
border-radius: 8px;
background: var(--secondary-color);
}
.divPostMenuDropdown.is-open {
display: flex;
}
.divPostMenuItem {
border: none;
border-radius: 5px;
background: transparent;
color: var(--primary-color);
text-align: left;
font-family: var(--font-family);
font-size: 14px;
cursor: pointer;
padding: 8px 10px;
}
.divPostMenuItem:hover {
background: var(--background-color);
color: var(--accent-color);
}
/* ************************************************************************* */
/* IMAGES */
/* ************************************************************************* */
/* All images: grayscale by default, 50% saturate on hover */
img {
filter: grayscale(var(--image-grayscale));
transition: filter 0.2s;
}
img:hover {
filter: grayscale(var(--image-grayscale-hover));
}