make_post_sell/make_post_sell/static/css/common.css
russell@unturf.com 18a8566023
feat: MPS-24 — operator-controlled tag order (no-JS + drag-and-drop ready)
The chip strip and lane sequence on the shop home page were locked to
tags_by_popularity (product_count desc, name asc). Fox wants shop
operators to set the order manually.

- New mps_tag.position column (Integer NOT NULL, server_default 0,
  idempotent migration 7f2a91c4d810). Smaller = earlier on the home
  chip strip / lanes / bulk-tagger list.
- tags_by_popularity now orders by (position asc, count desc, name
  asc). Fresh shops still get the popularity ordering — every row
  starts at position=0 so the next two clauses do the real work — but
  once an operator reorders, position wins.
- Two new POST actions on /s/{shop_id}/tags:
    action=reorder, tag_slug=<s>, direction=up|down  — no-JS path,
      swaps with the adjacent tag (positions normalised to dense
      0..N-1 first so a swap is always meaningful).
    action=set_order, tag_slugs=a,b,c,…              — single-POST
      "commit the whole order", for drag-and-drop. Any slug missing
      from the explicit list tails the order; we never silently drop
      a tag from the rendering.
- shop_tags.j2 grew up/down arrow forms per row (disabled on the
  first/last) plus a drag handle marked js-only. The grid template was
  bumped to seven columns (handle | chip | count | view | up | down |
  delete).
- tag_bulk.js gains onReorder: the form is intercepted via the
  existing maybeIntercept submit-capture; on a successful AJAX reorder
  we swap the row in the DOM and re-disable the up/down on whichever
  row is now first/last — no full page reload.

Tests (TestHomeLayoutAndTags): up, down, edge-no-op, set_order
drag-and-drop, and a render check confirming the new order surfaces on
the home chip strip. 28 in class pass (5 new).
2026-05-15 14:02:43 -04:00

5864 lines
139 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* * * * * *
*
* Make Post Sell (mps) is a mobile first web application. We make the pages
* look great on mobile & only use media queries as needed for bigger displays.
*
* We use CSS Grid. It's awesome.
*
* * * * * */
/* Preload hover background images to prevent flash */
body::after {
content: "";
position: absolute;
width: 0;
height: 0;
overflow: hidden;
z-index: -1;
background-image:
url("/static/img/trans-blue.png"),
url("/static/img/trans-green.png"),
url("/static/img/trans-red.png"),
url("/static/img/trans-blue2.png"),
url("/static/img/trans-green2.png"),
url("/static/img/trans-red2.png");
}
body {
margin: 0px;
font-family: var(--font-family, helvetica);
min-height: 100vh;
display: grid;
grid-template-rows: auto 1fr auto;
}
h1 {
font-size: 1.25em;
margin-top: 0;
margin-bottom: .4em;
}
/* Remove top margin from all heading tags */
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
}
table {
width: 100%;
}
/* Products editor: Status column hidden by default (desktop/landscape) */
.col-status { display: none; }
/* Mobile PORTRAIT only adjustments for products table */
@media (max-width: 640px) and (orientation: portrait) {
/* Let columns size naturally and tighten spacing */
.table-fixed-layout { table-layout: auto; }
.table-fixed-layout th, .table-fixed-layout td { padding: 6px; font-size: 14px; }
/* Hide low-priority columns: Visibility(3), Bundle(4), Physical(5), Ready(6) */
.table-fixed-layout th:nth-child(3), .table-fixed-layout td:nth-child(3),
.table-fixed-layout th:nth-child(4), .table-fixed-layout td:nth-child(4),
.table-fixed-layout th:nth-child(5), .table-fixed-layout td:nth-child(5),
.table-fixed-layout th:nth-child(6), .table-fixed-layout td:nth-child(6) {
display: none;
}
/* Show compact Status column (now header index 8, cell .col-status) */
.table-fixed-layout th.col-status, .table-fixed-layout td.col-status { display: table-cell; }
/* Allow Title (7) to wrap to multiple lines and keep bold */
.table-fixed-layout th:nth-child(7), .table-fixed-layout td:nth-child(7) {
white-space: normal;
width: 88px;
min-width: 88px;
max-width: 88px;
word-wrap: break-word;
overflow-wrap: break-word;
}
.table-fixed-layout td:nth-child(7) b {
font-weight: bold;
}
/* Make Sellable (1) and Price (2) sit closer together and more compact */
.table-fixed-layout th:nth-child(1), .table-fixed-layout td:nth-child(1) {
width: auto;
max-width: 66px;
min-width: 36px;
padding-right: 6px;
white-space: normal;
word-wrap: break-word;
overflow-wrap: break-word;
}
.table-fixed-layout th:nth-child(2), .table-fixed-layout td:nth-child(2) {
width: auto;
max-width: 65px;
min-width: 32px;
padding-left: 4px;
padding-right: 4px;
white-space: normal;
word-wrap: break-word;
overflow-wrap: break-word;
}
/* Constrain Size column (9) to give Title more space */
.table-fixed-layout th:nth-child(9), .table-fixed-layout td:nth-child(9) {
max-width: 66px;
min-width: 32px;
padding-left: 4px;
padding-right: 4px;
white-space: normal;
word-wrap: break-word;
font-size: 14px;
}
/* Ensure check/cross glyphs render consistently and add visual polish */
.table-fixed-layout td.col-status {
font-family: system-ui, "Segoe UI Symbol", "Noto Sans Symbols", "Apple Color Emoji",
"Noto Color Emoji", "Helvetica", "Arial", sans-serif;
padding: 8px 6px;
}
/* Align status lines with fixed-width labels for easier eye tracking */
.status-line {
display: flex;
gap: 2px;
margin-bottom: 4px;
align-items: baseline;
white-space: nowrap;
}
.status-line:last-child {
margin-bottom: 0;
}
.status-label {
display: inline-block;
min-width: 44px;
max-width: 44px;
text-align: left;
flex-shrink: 0;
margin-right: 3px;
}
.status-dot {
margin: 0 4px 0 2px;
}
.status-value {
flex-shrink: 0;
}
.decimal-dot {
font-weight: 700;
display: inline-block;
padding: 0 1px;
}
/* Allow Status column to wrap rows but keep each line intact */
.table-fixed-layout th.col-status, .table-fixed-layout td.col-status {
white-space: normal;
width: 84px;
min-width: 84px;
max-width: 84px;
}
/* Ensure table doesn't overflow on very small screens */
@media (max-width: 400px) {
.table-fixed-layout th:nth-child(1), .table-fixed-layout td:nth-child(1) { width: 52px; font-size: 13px; }
.table-fixed-layout th:nth-child(2), .table-fixed-layout td:nth-child(2) { width: 80px; font-size: 13px; }
.table-fixed-layout td:nth-child(9) { width: 50px; font-size: 13px; }
.table-fixed-layout th:nth-child(9) { width: 50px; }
.status-label { min-width: 56px; max-width: 56px; font-size: 13px; }
}
}
table tr:nth-child(even) {
/* Light gray background for even rows */
background-color: var(--surface-container, #f2f2f2);
}
table tr:nth-child(odd) {
/* White background for odd rows (optional, for contrast) */
background-color: var(--surface-base, #ffffff);
}
tr, th, td {
padding: 8px;
border: 0px;
text-align: left;
}
label {
display: block;
font-weight: bold;
}
span.asterisk {
color: red;
font-weight: bold;
}
a {
text-decoration: none;
color: var(--link-color, #5f6368);
}
input {
/* keep the input inside the parents box! */
box-sizing: border-box;
}
section {
margin-bottom: 0px;
}
input[type="text"],
input[type="tel"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="date"] {
padding: var(--space-2, 8px);
border-radius: var(--radius-sm, 4px);
border-style: solid;
border-width: 1px;
border-color: var(--input-border, #CCCCCC);
}
textarea {
/* keep the input inside the parents box! */
box-sizing: border-box;
padding: var(--space-2, 8px);
border-radius: var(--radius-sm, 4px);
border-style: solid;
border-width: 1px;
border-color: var(--input-border, #CCCCCC);
}
section.shop-name-and-description {
display: grid;
}
input.mps-quantity {
max-width: 60px;
}
input.mps-submit {
float: right;
}
textarea.mps-billing-address,
textarea.mps-shop-description,
textarea.mps-bundle-data,
textarea.mps-shop-ribbon-text
{
max-width: 600px;
width: 100%;
height: 120px;
padding: 10px;
}
textarea.mps-shop-ribbon-text {
height: 60px;
}
input.mps-shop-name,
input.mps-phone-number,
input.mps-google-analytics-id,
input.mps-stripe-public-api-key,
input.mps-stripe-secret-api-key,
input.mps-shop-ribbon-text-color,
input.mps-shop-ribbon-color
{
max-width: 600px;
width: 100%;
}
section.product-title-and-description,
section.content-title-and-description {
display: grid;
}
section.product-left,
section.content-left {
justify-self: right;
text-align: left;
/*max-width: 480px;*/
}
section.product-right,
section.content-right {
justify-self: center;
text-align: center;
}
section.log-in-form {
justify-self: right;
text-align: center;
}
section.join-form {
justify-self: left;
text-align: center;
}
/* ============================================
LOGIN CARD
============================================ */
.login-card {
max-width: 420px;
margin: var(--space-10) auto;
padding: var(--space-8) var(--space-6);
text-align: center;
background-color: var(--surface-base);
border-radius: var(--radius-lg);
border: 1px solid var(--border-light);
}
.login-card-title {
margin-bottom: var(--space-1);
}
.login-card-subtitle {
margin-bottom: var(--space-6);
color: var(--text-secondary);
}
.login-form {
display: grid;
gap: var(--space-3);
text-align: left;
}
.login-form-label {
margin-bottom: 0;
}
.login-form-input {
display: block;
width: 100%;
min-width: 0;
padding: var(--space-3) var(--space-4);
font-size: var(--text-base);
border: 2px solid var(--border-default);
border-radius: var(--radius-md);
background-color: var(--input-bg);
color: var(--input-text);
transition: border-color var(--duration-fast) var(--ease-standard);
}
.login-form-input:focus {
border-color: var(--border-focus);
outline: none;
}
.login-form-submit {
font-size: var(--text-base);
padding: var(--space-3) var(--space-4);
cursor: pointer;
}
.login-card-hint {
margin-top: var(--space-4);
padding: var(--space-3) var(--space-4);
background-color: var(--surface-dim);
border-radius: var(--radius-md);
text-align: left;
}
/* ============================================
LANDING PAGE (SaaS homepage, not logged in)
============================================ */
.landing-hero {
max-width: var(--content-width);
margin: var(--space-16) auto var(--space-12);
text-align: center;
padding: 0 var(--space-6);
}
.landing-hero-sub {
max-width: 540px;
margin: var(--space-4) auto var(--space-8);
color: var(--text-secondary);
}
.landing-hero-ctas {
display: grid;
grid-template-columns: auto auto;
gap: var(--space-4);
justify-content: center;
}
.landing-hero-ctas .mps-button {
min-width: 180px;
}
.landing-features {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-6);
max-width: var(--content-wide);
margin: 0 auto var(--space-12);
padding: 0 var(--space-6);
}
.landing-feature-card.well {
text-align: center;
padding: var(--space-8) var(--space-6);
}
.landing-feature-icon {
font-size: var(--text-4xl);
margin-bottom: var(--space-4);
}
.landing-feature-card h3 {
margin-bottom: var(--space-2);
}
.landing-cta-bottom {
max-width: var(--content-width);
margin: 0 auto var(--space-16);
padding: 0 var(--space-6);
}
.landing-cta-card.well {
text-align: center;
padding: var(--space-12) var(--space-8);
}
.landing-cta-card h2 {
margin-bottom: var(--space-3);
}
.landing-cta-card p {
margin-bottom: var(--space-6);
color: var(--text-secondary);
}
@media (max-width: 800px) {
.landing-hero {
margin: var(--space-10) auto var(--space-8);
}
.landing-hero-ctas {
grid-template-columns: 1fr;
}
.landing-hero-ctas .mps-button {
width: 100%;
}
.landing-features {
grid-template-columns: 1fr;
}
.login-card {
margin: var(--space-6) var(--space-3);
padding: var(--space-6) var(--space-4);
max-width: none;
}
}
@media (min-width: 801px) and (max-width: 1000px) {
.landing-features {
grid-template-columns: repeat(2, 1fr);
}
}
input.mps-product-title,
input.mps-product-price,
input.mps-content-title {
max-width: 600px;
width: 100%;
}
textarea.mps-product-description,
textarea.mps-content-description {
max-width: 600px;
width: 100%;
height: 120px;
padding: 10px;
}
input.file-input {
width: 100%;
}
div.message-ribbon {
height: 42px;
display: grid;
align-items: center;
text-align: center;
font-weight: bold;
font-size: 18px;
}
section.main {
overflow-x: hidden;
}
.environment-banner {
display: grid;
align-items: center;
text-align: center;
font-weight: bold;
font-size: var(--font-size-sm);
padding: var(--space-2) var(--space-4);
color: var(--color-white);
background-color: var(--color-warning, #e6a700);
}
.environment-banner-development {
background-color: var(--color-info, #3b82f6);
}
.trial-banner {
display: grid;
align-items: center;
text-align: center;
font-size: var(--font-size-sm);
padding: var(--space-2) var(--space-4);
background-color: var(--color-info, #3b82f6);
color: var(--color-white);
}
.trial-banner a {
color: var(--color-white);
text-decoration: underline;
}
.trial-banner-expired {
background-color: var(--color-error, #dc2626);
}
/*
section.grid-nav {
grid-column: 1/-1;
}
*/
/* mobile first */
/* the navbar is stacked by default. */
section.nav {
background-color: var(--bg-secondary);
display: grid;
grid-template-columns: 1fr;
grid-auto-columns: max-content;
grid-auto-flow: dense;
grid-gap: 4px;
padding: 4px;
}
div.message-ribbon {
display: none;
}
section.log-in {
text-align: center;
align-self: center;
font-size: .75em;
}
section.log-in a {
white-space: nowrap;
}
section.search {
align-self: center;
}
form.search {
width: 100%;
}
input.mps-keywords {
width: 100%;
text-align: center;
}
section.content {
background-color: var(--surface-base, #ffffff);
margin: 4px;
margin-bottom: 42px;
overflow-x: hidden;
}
section.logo{
text-align: center;
vertical-align: middle;
}
img {
width: 100%;
max-width: 100%;
height: auto;
box-sizing: border-box;
}
img.logo {
width: auto;
max-height: 100px;
max-width: 94%;
padding: 10px;
}
@media (max-width: 599px) {
img.logo {
max-width: 100%;
max-height: 100px;
padding: 6px;
}
}
@media (min-width: 600px) and (max-width: 959px) {
img.logo {
max-height: 60px;
padding: 8px;
}
}
img.product-cart-thumbnail {
border: 1px solid var(--border-default, #ddd);
border-radius: var(--radius-sm, 4px);
max-width:44px;
max-height:44px;
width: auto;
height: auto;
}
img.product-thumbnail {
border: 1px solid var(--border-default, #ddd);
border-radius: var(--radius-sm, 4px);
max-width:58px;
max-height:58px;
width: auto;
height: auto;
transition: border-color var(--duration-fast, 100ms) var(--ease-standard, ease);
}
/* Lit-up affordance when the JS hover-swap enhancement is active —
product-thumbnail-swap.js binds hover/click handlers; the visual cue
ships in CSS so it works without changing the markup. */
.product-images img.product-thumbnail:hover {
border-color: var(--color-navy, #5871ad);
}
.product-main {
max-height: 42vh;
}
.product-images {
text-align: left;
}
.product-images img.product-main,
div.product-images img.product-main {
max-width: 100%;
max-height: 42vh;
width: auto;
height: auto;
}
/* Video play button overlay for hero thumbnails */
.video-thumbnail-container {
position: relative;
display: inline-block;
cursor: pointer;
text-decoration: none;
}
.video-thumbnail-container img.product-main {
display: block;
max-width: 100%;
max-height: 42vh;
height: auto;
}
.video-play-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
width: 80px;
height: 80px;
background-color: rgba(255, 0, 0, 0.4); /* red at 66/255 ~= 0.26, try 0.4 for 66% visibility */
border-radius: 50%;
display: grid;
place-items: center;
pointer-events: none;
}
.video-play-overlay::after {
content: "";
width: 0;
height: 0;
border-style: solid;
border-width: 15px 0 15px 25px;
border-color: transparent transparent transparent #ffffff;
margin-left: 5px;
}
.video-click-to-play {
text-align: center;
margin-top: 8px;
color: inherit;
}
.video-thumbnail-container:hover .video-play-overlay {
background-color: rgba(255, 0, 0, 0.6);
}
/* Prevent content sections from overflowing */
.product-description {
max-width: 100%;
overflow-x: auto;
box-sizing: border-box;
overflow-wrap: break-word;
}
/* Use overflow-x: clip on .content so it clips without creating a scroll
container — overflow-x: auto breaks position: sticky for descendants */
.content,
section.content {
max-width: 100%;
overflow-x: clip;
box-sizing: border-box;
overflow-wrap: break-word;
}
/* Make pre and code tags horizontally scrollable for long content */
pre, code {
overflow-x: auto;
white-space: pre;
}
.mps-button {
/* Normalize so <button>, <a>, and <input type=submit> with this
class render consistently. inline-block (NOT grid) — buttons can
contain multiple inline children (icon span + label text, e.g.
the windows-95 hamburger) which must flow on one line. box-sizing
+ symmetric padding + explicit line-height fix the <button>-vs-<a>
rendering difference that made <button> elements look squished. */
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
border: 2px solid transparent;
border-radius: var(--radius-sm, 4px);
color: white;
background-color: #D4D0C8;
display: inline-block;
font-family: inherit;
font-size: var(--text-sm, 14px);
font-weight: var(--weight-bold, bold);
line-height: 1.4;
min-width: 100%;
min-height: 44px;
margin-top: var(--space-1, 4px);
margin-bottom: var(--space-1, 4px);
padding: 12px 18px;
text-align: center;
text-decoration: none;
white-space: nowrap;
cursor: pointer;
vertical-align: middle;
}
[data-theme="dark"] .mps-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue.png");
color: var(--blue-color);
border: 2px solid var(--blue-color);
}
[data-theme="dark"] .mps-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue2.png");
color: #ffffff;
border: 2px solid var(--blue-color);
}
a.mps-button-blue,
button.mps-button-blue {
background-color: var(--color-blue, #98b6fa);
}
[data-theme="dark"] a.mps-button-blue,
[data-theme="dark"] button.mps-button-blue,
[data-theme="dark"] input.mps-button-blue {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue.png");
color: var(--blue-color);
border: 2px solid var(--blue-color);
}
[data-theme="dark"] a.mps-button-blue:hover,
[data-theme="dark"] button.mps-button-blue:hover,
[data-theme="dark"] input.mps-button-blue:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue2.png");
color: #ffffff;
border: 2px solid var(--blue-color);
}
a.mps-button-green,
button.mps-button-green {
background-color: var(--color-green, #a3c765);
}
[data-theme="dark"] a.mps-button-green,
[data-theme="dark"] button.mps-button-green,
[data-theme="dark"] input.mps-button-green {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
color: var(--green-color);
border: 2px solid var(--green-color);
}
[data-theme="dark"] a.mps-button-green:hover,
[data-theme="dark"] button.mps-button-green:hover,
[data-theme="dark"] input.mps-button-green:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
color: #ffffff;
border: 2px solid var(--green-color);
}
a.mps-button-red,
button.mps-button-red,
input.mps-button-red {
background-color: var(--red-color, #bc2131);
opacity: 0.8;
}
[data-theme="dark"] a.mps-button-red,
[data-theme="dark"] button.mps-button-red,
[data-theme="dark"] input.mps-button-red {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red.png");
color: var(--red-color);
border: 2px solid var(--red-color);
opacity: 1.0;
}
[data-theme="dark"] a.mps-button-red:hover,
[data-theme="dark"] button.mps-button-red:hover,
[data-theme="dark"] input.mps-button-red:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red2.png");
color: #ffffff;
border: 2px solid var(--red-color);
}
.mps-cancel-button,
.mps-comment-form-button {
display: inline-block;
padding: 6px 12px;
border: 1px solid var(--input-border, #ccc);
border-radius: var(--radius-sm, 4px);
background: var(--surface-dim, #f9f9f9);
color: var(--text-primary, #333);
font-size: var(--text-sm, 14px);
cursor: pointer;
margin: 0;
text-decoration: none;
vertical-align: top;
box-sizing: border-box;
}
/* Red cancel button */
.mps-cancel-button-red {
background: var(--red-color);
color: white;
border-color: var(--red-color);
}
[data-theme="dark"] .mps-cancel-button-red {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red.png");
border: 2px solid var(--red-color);
color: var(--red-color);
font-weight: bold;
}
[data-theme="dark"] .mps-cancel-button-red:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red2.png");
color: #ffffff;
border: 2px solid var(--red-color);
}
.comment-actions {
margin-bottom: 42px;
display: grid;
grid-auto-flow: column;
grid-template-columns: repeat(auto-fit, max-content);
justify-content: start;
gap: 5px;
}
.reply-link,
.edit-link,
.delete-link,
.moderate-link {
display: inline-block;
padding: 6px 12px;
border: 1px solid var(--input-border, #ccc);
border-radius: var(--radius-sm, 4px);
background: var(--surface-dim, #f9f9f9);
color: var(--text-primary, #333);
font-size: var(--text-sm, 14px);
cursor: pointer;
margin: 0;
text-decoration: none;
vertical-align: top;
box-sizing: border-box;
}
/* Light mode color styling */
.reply-link {
background: var(--green-color);
color: white;
border: 2px solid transparent;
font-weight: bold;
}
.delete-link {
background: var(--red-color);
color: white;
border: 2px solid transparent;
font-weight: bold;
}
.mps-comment-form-button {
background: var(--green-color);
color: white;
border: 2px solid transparent;
font-weight: bold;
}
[data-theme="dark"] .reply-link,
[data-theme="dark"] .edit-link,
[data-theme="dark"] .moderate-link {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue.png");
border: 2px solid var(--blue-color);
color: var(--blue-color);
font-weight: bold;
}
[data-theme="dark"] .reply-link:hover,
[data-theme="dark"] .edit-link:hover,
[data-theme="dark"] .moderate-link:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue2.png");
color: #ffffff;
border: 2px solid var(--blue-color);
}
/* Reply button - green */
[data-theme="dark"] .reply-link {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
border: 2px solid var(--green-color);
color: var(--green-color);
font-weight: bold;
}
[data-theme="dark"] .reply-link:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
color: #ffffff;
border: 2px solid var(--green-color);
}
/* Delete button - red */
[data-theme="dark"] .delete-link {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red.png");
border: 2px solid var(--red-color);
color: var(--red-color);
font-weight: bold;
}
[data-theme="dark"] .delete-link:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red2.png");
color: #ffffff;
border: 2px solid var(--red-color);
}
/* Post comment button - green */
[data-theme="dark"] .mps-comment-form-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
border: 2px solid var(--green-color);
color: var(--green-color);
font-weight: bold;
}
[data-theme="dark"] .mps-comment-form-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
color: #ffffff;
border: 2px solid var(--green-color);
}
.payment-toggle-button {
display: inline-block;
padding: 6px 12px;
border: 1px solid var(--input-border, #ccc);
border-radius: var(--radius-sm, 4px);
background: var(--surface-dim, #f9f9f9);
color: var(--text-primary, #333);
font-size: var(--text-sm, 14px);
cursor: pointer;
margin: 0;
text-decoration: none;
vertical-align: top;
box-sizing: border-box;
}
.payment-toggle-button.enable {
background: #4a4;
color: white;
border-color: #4a4;
}
.payment-toggle-button.disable {
background: #d44;
color: white;
border-color: #d44;
}
a.product-edit-button {
background-color: var(--color-blue, #98b6fa);
}
[data-theme="dark"] a.mps-button.product-edit-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue.png");
color: #7ab9ff;
border: 2px solid #7ab9ff;
}
[data-theme="dark"] a.mps-button.product-edit-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue2.png");
color: #ffffff;
border: 2px solid #7ab9ff;
}
[data-theme="dark"] a.mps-button.shop-new-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
color: var(--green-color);
border: 2px solid var(--green-color);
}
[data-theme="dark"] a.mps-button.shop-new-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
color: #ffffff;
border: 2px solid var(--green-color);
}
/* Product download and preview buttons - make them green in dark mode */
[data-theme="dark"] a.product-download-button,
[data-theme="dark"] button.product-download-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
color: var(--green-color);
border: 2px solid var(--green-color);
}
[data-theme="dark"] a.product-download-button:hover,
[data-theme="dark"] button.product-download-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
color: #ffffff;
border: 2px solid var(--green-color);
}
[data-theme="dark"] a.product-preview-button,
[data-theme="dark"] button.product-preview-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
color: var(--green-color);
border: 2px solid var(--green-color);
}
[data-theme="dark"] a.product-preview-button:hover,
[data-theme="dark"] button.product-preview-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
color: #ffffff;
border: 2px solid var(--green-color);
}
a.product-preview-button {
background-color: var(--color-blue, #98b6fa);
}
a.product-download-button {
background-color: var(--color-green, #a3c765);
}
a.product-new-button {
background-color: var(--color-blue, #98b6fa);
}
a.shop-new-button {
background-color: var(--color-green, #a3c765);
}
a.done-button {
background-color: var(--color-green, #a3c765);
}
a.log-out-button {
background-color: var(--red-color);
}
[data-theme="dark"] a.log-out-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red.png");
border: 2px solid var(--red-color);
color: var(--red-color);
}
[data-theme="dark"] a.log-out-button:hover {
background-image: url("/static/img/trans-red2.png");
color: #ffffff;
border: 2px solid var(--red-color);
}
a.shop-switch-button {
color: var(--text-secondary, #666666);
border-color: var(--text-secondary, #666666);
border-style: solid;
border-width: 1px;
padding-top: 10px;
padding-bottom: 10px;
}
a.user-display-name {
margin: 14px;
display: inline-block;
white-space: nowrap;
}
a.cart-and-count {
margin: 14px;
display: inline-block;
white-space: nowrap;
}
/* -------------------------------------------------------------------
Form-buttons: copy your <a>-class styles to <button> elements
------------------------------------------------------------------- */
/* “Remove” link: no button chrome, just a link color + hover underline */
button.cart-remove-link {
background: none;
border: none;
padding: 0;
font: inherit;
color: var(--link-color, #5f6368);
text-decoration: none;
cursor: pointer;
}
button.cart-remove-link:hover {
text-decoration: underline;
}
/* Links should use the theme link color */
[data-theme="dark"] a {
color: var(--link-color);
}
[data-theme="dark"] button.cart-remove-link {
color: var(--blue-color);
}
[data-theme="dark"] button.cart-remove-link:hover {
color: var(--blue-color);
text-decoration: underline;
}
/* “Add To Cart”, “Download”, “Preview” buttons */
button.product-download-button,
button.product-preview-button {
/* inherits .mps-button defaults */
}
button.product-download-button {
background-color: var(--color-green, #a3c765);
}
button.product-preview-button {
background-color: var(--color-blue, #98b6fa);
}
/* Cart action buttons */
button.cart-checkout-button {
background-color: var(--color-green, #a3c765);
}
button.cart-save-button {
background-color: var(--color-blue, #98b6fa);
}
/* Dark mode cart buttons */
[data-theme="dark"] button.cart-checkout-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
color: var(--green-color);
border: 2px solid var(--green-color);
}
[data-theme="dark"] button.cart-checkout-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
color: #ffffff;
border: 2px solid var(--green-color);
}
button.cart-activate-button {
background-color: var(--color-navy, #5871ad);
}
button.cart-delete-button {
background-color: var(--color-danger, #CC6958);
color: white;
}
/* “Make Public” / “Make Private” */
button.cart-public-button {
background: none;
color: var(--text-secondary, #666666);
border: 1px solid var(--text-secondary, #666666);
padding-top: 10px;
padding-bottom: 10px;
cursor: pointer;
}
button.cart-public-button span.lock {
font-size: 24px;
}
/* Continue shopping button */
.cart-continue-shopping {
display: grid;
justify-items: center;
margin-top: var(--space-3, 12px);
}
.cart-continue-shopping-button {
background-color: var(--color-blue, #98b6fa);
color: white;
}
/* Empty cart state — stacked buttons that fill the well so they line up
exactly with the right column's Make Cart Active / Delete Cart pair.
Same button width across both wells = one cohesive button rhythm. */
.cart-empty-state {
display: grid;
gap: var(--space-2, 8px);
padding: var(--space-4, 16px) var(--space-3, 12px);
text-align: center;
}
.cart-empty-state h2 {
margin: 0;
}
.cart-empty-hint {
margin: 0;
color: var(--text-muted, #777);
}
.cart-empty-actions {
display: grid;
gap: var(--space-2, 8px);
margin-top: var(--space-3, 12px);
}
.cart-empty-actions .mps-button {
width: 100%;
}
.coupon-apply-button {
background-color: var(--color-green, #a3c765);
}
/*
* CSS Grid Lanes: Masonry-style layout with graceful fallback
*
* Grid Lanes is a new CSS feature that creates true masonry layouts natively.
* We use @supports to detect browser support and fall back to regular CSS Grid.
* Shop owners can toggle this via the "grid-lanes-enabled" class in settings.
*
* Fallback: Standard CSS Grid with auto-fit columns (items in rows)
* Enhanced: CSS Grid Lanes (items flow into shortest column, waterfall style)
*/
/* Default: Standard CSS Grid layout */
section.serp {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
grid-auto-columns: max-content;
grid-auto-flow: dense;
gap: 4px;
}
/* Grid Lanes: Only apply when shop has it enabled AND browser supports it */
@supports (display: grid-lanes) {
section.serp.grid-lanes-enabled {
display: grid-lanes;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 4px;
/* item-tolerance controls sensitivity when deciding item placement */
/* Prevents layout shuffling from minor size variations */
item-tolerance: 1em;
}
}
div.serp-item {
border-radius: var(--radius-sm, 4px);
padding: var(--space-1, 4px);
grid-column: span 1;
grid-row: span 1;
/* Grid items default to min-width: auto — a wide img inside would
push the cell past minmax(160px, 1fr) and collapse the auto-fit
grid to one full-viewport column. Force min-width: 0 so the
child img's max-width: 100% actually clamps. Same gotcha as the
lane tiles below. */
min-width: 0;
/* The new CSS animations are off the hook. */
transition: background-color 800ms ease;
-webkit-transition: 600ms -webkit-filter ease;
-moz-transition: 600ms -moz-filter ease;
-moz-transition: 600ms filter ease;
-ms-transition: 600ms -ms-filter ease;
-o-transition: 600ms -o-filter ease;
transition: 600ms filter ease, 600ms -webkit-filter ease;
}
div.serp-item:hover {
background-color: #FBFBF3;
-webkit-filter: brightness(88%);
-moz-filter: brightness(88%);
filter: brightness(88%);
}
[data-theme="dark"] div.serp-item:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue2.png");
border: 2px solid #7ab9ff;
color: #ffffff;
-webkit-filter: none;
-moz-filter: none;
filter: none;
}
[data-theme="dark"] div.serp-item:hover a {
color: #ffffff;
}
img.serp-thumbnail {
/* width: auto + max-width: 100% per CLAUDE.md CSS Media Sizing:
lets the image shrink to fit its grid cell without forcing the
cell to expand to the image's natural width (which on
printableprompts is 1080px+ and was collapsing the auto-fit
grid to a single full-viewport column). */
width: auto;
max-width: 100%;
height: auto;
display: block;
border-radius: var(--radius-sm, 4px);
}
/* ---------- MPS-24: tag chips, chip strip, sectioned lanes ---------- */
/* Chip strip sits above the grid; auto-flow column so chips line up, with
horizontal overflow on narrow viewports so mobile can swipe through them. */
nav.tag-chip-strip {
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
gap: var(--space-2, 8px);
padding: var(--space-2, 8px) var(--space-1, 4px);
margin: 0 0 var(--space-3, 12px) 0;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
scrollbar-width: thin;
}
a.tag-chip {
display: inline-grid;
place-items: center;
padding: var(--space-1, 4px) var(--space-3, 12px);
border: 1px solid var(--color-border, #d1d5db);
border-radius: var(--radius-pill, 999px);
background: var(--color-surface, #fff);
color: var(--color-text, #111);
font-size: var(--type-body-sm-size, 0.875rem);
text-decoration: none;
transition: background-color 150ms ease, border-color 150ms ease;
}
a.tag-chip:hover {
background: var(--color-surface-2, #f3f4f6);
border-color: var(--color-border-strong, #9ca3af);
text-decoration: none;
}
a.tag-chip-active {
background: var(--color-accent, #5871AD);
border-color: var(--color-accent, #5871AD);
color: var(--color-on-accent, #fff);
}
a.tag-chip-active:hover {
background: var(--color-accent-strong, #4860a0);
color: var(--color-on-accent, #fff);
}
[data-theme="dark"] a.tag-chip {
background: var(--dark-button-bg, #2d3748);
border-color: var(--dark-border, #475569);
color: #fff;
}
[data-theme="dark"] a.tag-chip:hover {
background: var(--dark-button-bg-hover, #3a4658);
}
/* Sectioned-lanes layout — one lane per top tag. Netflix-style
horizontal row with scroll-snap. */
section.tag-lane {
margin: 0 0 var(--space-6, 24px) 0;
}
header.tag-lane-header {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
margin: 0 0 var(--space-2, 8px) 0;
padding: 0 var(--space-1, 4px);
}
h2.tag-lane-title {
margin: 0;
}
a.tag-lane-more {
font-size: var(--type-body-sm-size, 0.875rem);
text-decoration: none;
}
a.tag-lane-more:hover {
text-decoration: underline;
}
div.tag-lane-grid {
/* Horizontal scrolling row of fixed-width tiles. grid-auto-flow:
column lays children in a single row left-to-right; overflow-x
auto provides the scroll. scroll-snap-type x mandatory makes
swipe snap to tile edges. Grid-only per CLAUDE.md (no flexbox). */
display: grid;
grid-auto-flow: column;
grid-auto-columns: minmax(160px, 200px);
gap: var(--space-2, 8px);
overflow-x: auto;
overflow-y: hidden;
padding: var(--space-1, 4px) 0 var(--space-2, 8px) 0;
scroll-snap-type: x mandatory;
scrollbar-width: thin;
}
div.tag-lane-tile {
/* Tiles sit inside the horizontal scroll row. The default
.serp-item rules (hover, transition, border-radius) still
apply since we kept that class on the tile element. */
scroll-snap-align: start;
/* Make the whole tile occupy its grid track. */
width: 100%;
/* CRITICAL: grid items default to min-width: auto, which lets a
large img inside push the grid track past grid-auto-columns'
max (200px). Forcing min-width: 0 makes the track respect the
cap — without this, a 1500×1500 marketing thumbnail (e.g.
printableprompts "Color With Kindness") explodes its tile
across the full viewport. Same fix on min-width: 0 for the img
belt-and-suspenders so max-width: 100% can actually clamp. */
min-width: 0;
}
div.tag-lane-tile img.serp-thumbnail {
/* Per CLAUDE.md CSS Media Sizing: width auto + max-width 100% +
max-height. Never combine width: 100% with max-height —
portrait thumbs leave a little whitespace, which is acceptable.
min-width: 0 lets max-width: 100% actually clamp (see the tile
rule above for the grid-item min-content gotcha). */
width: auto;
max-width: 100%;
max-height: 200px;
min-width: 0;
}
@media (max-width: 800px) {
/* Mobile: narrower tiles + breathing room on the swipe edge */
div.tag-lane-grid {
grid-auto-columns: minmax(140px, 160px);
padding-right: var(--space-4, 16px);
}
div.tag-lane-tile img.serp-thumbnail {
max-height: 160px;
}
}
/* Tag editor bulk list */
ul.tag-list {
list-style: none;
padding: 0;
margin: var(--space-3, 12px) 0;
display: grid;
gap: var(--space-2, 8px);
}
li.tag-list-item {
display: grid;
/* handle | chip | count | view | up | down | delete */
grid-template-columns: auto auto 1fr auto auto auto auto;
align-items: center;
gap: var(--space-3, 12px);
padding: var(--space-2, 8px);
border: 1px solid var(--color-border, #e5e7eb);
border-radius: var(--radius-sm, 4px);
}
li.tag-list-item.tag-list-drop-target {
/* Active drop position during drag-and-drop reordering. */
background: color-mix(in srgb, var(--color-green, #a3c765) 14%, var(--surface-base, #fff) 86%);
}
span.tag-list-handle {
cursor: grab;
color: var(--text-muted, #777);
font-size: var(--text-md, 1.1rem);
user-select: none;
line-height: 1;
}
form.tag-list-reorder { margin: 0; }
form.tag-list-reorder button[disabled] {
opacity: 0.4;
cursor: not-allowed;
}
span.tag-list-count {
color: var(--color-text-muted, #6b7280);
font-size: var(--type-body-sm-size, 0.875rem);
}
ul.tag-product-list {
list-style: none;
padding: 0;
margin: var(--space-3, 12px) 0;
display: grid;
gap: var(--space-1, 4px);
}
li.tag-product-row {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-3, 12px);
padding: var(--space-1, 4px) 0;
}
form.tag-product-toggle,
form.tag-list-delete {
margin: 0;
}
/* MPS-24 Phase 2: tag-suggestion well */
h3.tag-suggest-heading {
margin: var(--space-4, 16px) 0 var(--space-2, 8px) 0;
}
ul.tag-suggest-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: var(--space-2, 8px);
}
li.tag-suggest-item {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-1, 4px);
padding: var(--space-3, 12px);
border: 1px solid var(--color-border, #e5e7eb);
border-radius: var(--radius-sm, 4px);
background: var(--color-surface-2, #f9fafb);
}
div.tag-suggest-label {
display: grid;
grid-template-columns: auto 1fr;
align-items: baseline;
gap: var(--space-2, 8px);
}
div.tag-suggest-samples {
color: var(--color-text-muted, #6b7280);
font-size: var(--type-body-sm-size, 0.875rem);
}
span.tag-suggest-sample {
/* inline tokens — no display: change, lets samples wrap naturally */
}
div.tag-suggest-actions {
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
gap: var(--space-2, 8px);
margin-top: var(--space-2, 8px);
}
form.tag-suggest-form {
margin: 0;
}
/* MPS-24 Phase 2.4: SPA flash toasts on the bulk tagger */
div.tag-flash {
display: grid;
gap: var(--space-2, 8px);
margin: 0 0 var(--space-3, 12px) 0;
}
div.tag-flash-toast {
padding: var(--space-2, 8px) var(--space-3, 12px);
border-radius: var(--radius-sm, 4px);
border: 1px solid var(--color-border, #d1d5db);
background: var(--color-surface-2, #f9fafb);
color: var(--color-text, #111);
transition: opacity 400ms ease;
}
div.tag-flash-success {
background: var(--color-success-subtle, #ecfdf5);
border-color: var(--color-success, #10b981);
color: var(--color-success-strong, #065f46);
}
div.tag-flash-error {
background: var(--color-danger-subtle, #fef2f2);
border-color: var(--color-danger, #ef4444);
color: var(--color-danger-strong, #991b1b);
}
div.tag-flash-info {
background: var(--color-info-subtle, #eff6ff);
border-color: var(--color-info, #3b82f6);
color: var(--color-info-strong, #1e40af);
}
/* Tag detail page header */
section.tag-detail-header {
margin: var(--space-3, 12px) 0;
}
@media (max-width: 800px) {
/* Mobile: chips swipe horizontally; lanes already stack via single-col grid */
nav.tag-chip-strip {
padding-right: var(--space-4, 16px); /* breathing room at the swipe edge */
}
}
div.edit-page {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-4, 16px);
max-width: 1200px;
margin: 0 auto;
padding: var(--space-3, 12px);
}
@media (min-width: 720px) {
div.edit-page {
grid-template-columns: repeat(2, 1fr);
}
}
/* Wells on the edit page get more breathing room than the default. */
div.edit-page > section.well2 {
padding: var(--space-4, 16px) var(--space-5, 20px);
}
div.edit-page > section.well2 > h3:first-child,
div.edit-page > section.well2 > form > h3:first-child {
margin-top: 0;
font-size: 1.125rem;
font-weight: 600;
}
/* Pricing-mode fieldset on edit page — improved spacing. */
div.edit-page fieldset {
border: 1px solid var(--color-border, #ddd);
border-radius: var(--radius-md, 8px);
padding: var(--space-3, 12px) var(--space-4, 16px);
margin: var(--space-3, 12px) 0;
}
div.edit-page fieldset legend {
padding: 0 var(--space-2, 8px);
font-weight: 600;
color: var(--color-text-muted, #666);
}
div.edit-page fieldset label[style*="display:block"],
div.edit-page fieldset label.visibility_radio {
line-height: 1.6;
}
/* Override: section.product-title-and-description uses display:grid by
default to lay out product/content pages. On the edit page, the form
inside it should flow as normal block layout — no grid splitting. */
div.edit-page > section.product-title-and-description {
display: block;
}
/* File metadata line — File Type · File Size on a single line.
Used in the upload/preview/thumbnail blocks of the edit page. */
.file-meta {
margin: var(--space-1, 4px) 0;
color: var(--color-text-muted, #666);
font-size: 0.9em;
}
.file-meta-item {
display: inline-block;
}
.file-meta-item + .file-meta-item::before {
content: " · ";
color: var(--color-text-muted, #aaa);
margin: 0 var(--space-1, 4px);
}
.file-meta.total-capacity {
margin-top: var(--space-2, 8px);
margin-bottom: var(--space-3, 12px);
}
/* Thumbnail label — clearly identifies thumbnail1 / thumbnail2 / etc. */
.upload-thumbnail-item .thumbnail-label {
font-family: monospace;
font-size: 0.95rem;
font-weight: 600;
margin: 0 0 var(--space-2, 8px);
color: var(--color-text-primary, #333);
}
/* Form helper text — small tag below labels that doesn't break layout. */
.form-help {
display: block;
color: var(--color-text-muted, #666);
font-size: 0.85em;
margin: var(--space-1, 4px) 0 var(--space-2, 8px);
}
/* Textarea inside a well should fill the available width up to a
readable cap. Was capped at 600px which leaves dead space in wide
2-column wells. */
div.edit-page textarea.mps-product-description,
div.edit-page textarea.mps-content-description {
max-width: 100%;
}
/* ── Edit-page Material cards ───────────────────────────────────────────
Wells on the edit page get card-style elevation, rounded corners,
border accent, and a subtle hover lift. The goal: each section
reads as a discrete step the owner can act on. */
div.edit-page > section.well2 {
background: var(--surface, #fff);
border-radius: var(--radius-lg, 12px);
box-shadow: var(--elevation-1, 0 1px 3px rgba(0,0,0,0.06));
border: 1px solid var(--color-border, #eee);
transition: box-shadow var(--motion-fast, 150ms) ease,
transform var(--motion-fast, 150ms) ease;
}
div.edit-page > section.well2:hover,
div.edit-page > section.well2:focus-within {
box-shadow: var(--elevation-3, 0 4px 12px rgba(0,0,0,0.07));
}
/* Card header — h3 with leading icon. Class .edit-card-icon turns
any inline glyph into a 36px circular badge. (Grid only.) */
div.edit-page > section.well2 > h3:first-child,
div.edit-page > section.well2 > form > h3:first-child {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-3, 12px);
margin-bottom: var(--space-3, 12px);
padding-bottom: var(--space-3, 12px);
border-bottom: 1px solid var(--color-border, #eee);
color: var(--color-text-primary, #222);
}
.edit-card-icon {
display: inline-grid;
place-items: center;
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--color-blue-tint, #e8efff);
color: var(--color-navy, #5871ad);
font-size: 1.1rem;
}
/* Status pill — lives in the call_to_action block (top-right of page,
alongside permanent link). Surfaces visibility + ready state + price
at a glance. No background since it sits in the page header area.
Container uses text-align: right and lets the inline-grid pills flow
and wrap naturally — no flex. */
.edit-status-bar {
text-align: right;
margin: 0 0 var(--space-2, 8px);
line-height: 2;
}
.edit-permanent-link {
text-align: right;
margin: 0;
color: var(--color-text-muted, #666);
font-size: 0.85em;
}
.edit-status-pill {
display: inline-grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
align-items: center;
gap: var(--space-1, 4px);
margin-left: var(--space-2, 8px);
padding: var(--space-1, 4px) var(--space-3, 12px);
border-radius: var(--radius-pill, 999px);
font-size: 0.85em;
font-weight: 600;
background: var(--color-text-muted, #888);
color: #fff;
}
.edit-status-pill-ready {
background: var(--color-green-dark, #8ab34e);
}
.edit-status-pill-incomplete {
background: var(--color-gold, #d4a843);
color: #333;
}
.edit-status-pill-public {
background: var(--color-blue, #5871ad);
}
.edit-status-pill-private {
background: var(--color-text-muted, #888);
}
.edit-status-pill-unlisted {
background: var(--color-purple, #9B59B6);
}
/* Primary save action — filled, prominent button. */
div.edit-page input.mps-submit[value="Save Settings"],
div.edit-page button.mps-submit-primary,
.mps-button-primary {
float: none;
box-sizing: border-box;
display: inline-block;
line-height: 1.4;
text-align: center;
padding: var(--space-3, 12px) var(--space-6, 24px);
background: var(--color-navy, #5871ad);
color: #fff;
border: 1px solid var(--color-navy, #5871ad);
border-radius: var(--radius-md, 8px);
font-weight: 600;
font-size: 1rem;
box-shadow: var(--elevation-1, 0 1px 3px rgba(0,0,0,0.12));
cursor: pointer;
transition: background var(--motion-fast, 150ms) ease,
box-shadow var(--motion-fast, 150ms) ease;
}
div.edit-page input.mps-submit[value="Save Settings"]:hover,
div.edit-page button.mps-submit-primary:hover,
.mps-button-primary:hover {
background: var(--color-navy-dark, #44588a);
box-shadow: var(--elevation-2, 0 2px 6px rgba(0,0,0,0.15));
}
div.edit-page input.mps-submit[value="Save Settings"]:disabled,
div.edit-page button.mps-submit-primary:disabled,
.mps-button-primary:disabled {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* Sticky save bar at the bottom of the edit page. (Grid only.) */
.edit-save-bar {
position: sticky;
bottom: var(--space-3, 12px);
margin-top: var(--space-5, 20px);
padding: var(--space-3, 12px) var(--space-4, 16px);
background: var(--surface, #fff);
border-radius: var(--radius-md, 8px);
box-shadow: var(--elevation-3, 0 4px 12px rgba(0,0,0,0.07));
border: 1px solid var(--color-border, #eee);
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: var(--space-3, 12px);
z-index: 10;
}
.edit-save-bar-status {
color: var(--color-text-muted, #666);
font-size: 0.9em;
}
/* Full-width edit card — spans both columns of the 2-col edit grid.
Used for sections that have grid layouts of their own (thumbnails,
bundle products) where 1 column doesn't give enough room. */
div.edit-page > section.edit-card-full {
grid-column: 1 / -1;
}
/* Make-an-offer form (expanded from the <details> on product pages).
Grid layout gives consistent vertical rhythm — the inputs and label
would otherwise sit flush against each other and against the
summary button above. */
.product-offer-form,
.offer-action-form {
display: grid;
gap: var(--space-3, 12px);
margin-top: var(--space-3, 12px);
}
.product-offer-form label,
.offer-action-form label {
margin: 0;
}
.product-offer-form input[type="number"],
.product-offer-form input[type="text"],
.offer-action-form input[type="number"],
.offer-action-form input[type="text"] {
width: 100%;
box-sizing: border-box;
padding: var(--space-2, 8px) var(--space-3, 12px);
}
/* Inline flash for the offer.js progressive-enhancement layer. */
.offer-js-flash {
margin: var(--space-2, 8px) 0 0;
padding: var(--space-2, 8px) var(--space-3, 12px);
border-radius: var(--radius-sm, 4px);
font-size: 0.9em;
}
.offer-js-flash:empty { display: none; }
.offer-js-flash-error {
background: var(--color-danger, #CC6958);
color: #fff;
}
.offer-js-flash-info {
background: var(--surface-dim, #f9f9fa);
color: var(--text-muted, #666);
}
/* State notice banner on the offer detail page (offer.j2). Reuses the
.alert color variants; this just gives it block spacing/shape since
the base .alert rule is laid out for the dismissible flash strip. */
.offer-state-notice {
margin: var(--space-3, 12px) 0;
padding: var(--space-2, 8px) var(--space-4, 16px);
border-radius: var(--radius-md, 8px);
}
/* Accepted-offer pay-link row shown to the seller: an input pre-filled
with the buyer's pay URL plus a copy-to-clipboard button. */
.offer-pay-link-row {
display: grid;
grid-template-columns: 1fr auto;
gap: var(--space-2, 8px);
margin-top: var(--space-3, 12px);
}
.offer-pay-link {
width: 100%;
box-sizing: border-box;
padding: var(--space-2, 8px) var(--space-3, 12px);
font-family: var(--font-mono, ui-monospace, monospace);
font-size: var(--text-sm, 0.875rem);
}
/* Design-system settings form: stacked label + control + hint per
field, two-up grid on wider viewports. Grid only — no flex. */
.settings-form {
display: grid;
gap: var(--space-4, 16px);
margin-top: var(--space-3, 12px);
}
.settings-form-grid {
display: grid;
gap: var(--space-4, 16px);
}
@media (min-width: 640px) {
.settings-form-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
.settings-field {
display: grid;
gap: var(--space-1, 4px);
align-content: start;
}
.settings-field--full { grid-column: 1 / -1; }
.settings-field > label {
margin: 0;
font-weight: 600;
}
.settings-field--inline {
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-2, 8px);
font-weight: 600;
}
.settings-field input[type="number"],
.settings-field input[type="text"] {
width: 100%;
max-width: 18rem;
box-sizing: border-box;
padding: var(--space-2, 8px) var(--space-3, 12px);
}
.settings-field-hint {
color: var(--text-muted, #777);
font-size: var(--text-sm, 0.875rem);
}
.settings-form-actions {
display: grid;
grid-template-columns: 1fr auto;
}
.settings-form-actions .mps-submit { grid-column: 2; }
/* Public user profile (profile.j2). Grid only. */
.profile-page { display: grid; gap: var(--space-4, 16px); }
.profile-card-header {
display: grid;
grid-template-columns: auto 1fr;
gap: var(--space-4, 16px);
align-items: center;
}
.profile-avatar {
width: 80px;
height: 80px;
border-radius: var(--radius-md, 8px);
background: var(--surface-dim, #f9f9fa);
}
.profile-identity h1 { margin: 0; }
.profile-handle,
.profile-meta {
margin: var(--space-1, 4px) 0 0;
color: var(--text-muted, #777);
font-size: var(--text-sm, 0.875rem);
}
.profile-email-reveal { margin-top: var(--space-3, 12px); }
.profile-email-reveal summary {
cursor: pointer;
font-weight: 600;
}
.profile-email { margin: var(--space-2, 8px) 0 0; }
.profile-shop-list {
margin: var(--space-2, 8px) 0 0;
padding-left: var(--space-4, 16px);
display: grid;
gap: var(--space-1, 4px);
}
/* Shop offers inbox (shop_offers.j2) + buyer-side /u/offers + /u/bids.
The pages share the .shop-offers-page wrapper so the layout overrides
apply to all three. Wider than .one-column's 600px default so the
table doesn't word-wrap the product titles on desktop. */
section.one-column.shop-offers-page {
max-width: 1100px;
}
.shop-offers-table {
width: 100%;
border-collapse: collapse;
table-layout: auto;
}
.shop-offers-table th,
.shop-offers-table td {
text-align: left;
padding: var(--space-2, 8px) var(--space-3, 12px);
border-bottom: 1px solid var(--input-border, #e0e0e0);
vertical-align: middle;
}
/* Product column takes the available width; the rest are content-sized. */
.shop-offers-table th:first-child,
.shop-offers-table td:first-child { width: auto; }
.shop-offers-table th.col-narrow,
.shop-offers-table td.col-narrow { white-space: nowrap; }
.shop-offers-table th.col-action,
.shop-offers-table td.col-action {
text-align: right;
white-space: nowrap;
}
.shop-offers-table tr.offer-row-needs-action {
background: var(--alert-info-bg, #dce8ff);
}
.shop-offers-table tr.offer-row-terminal { opacity: 0.7; }
.offer-row-flag {
margin-left: var(--space-2, 8px);
font-size: var(--text-xs, 0.75rem);
font-weight: bold;
text-transform: uppercase;
color: var(--color-primary, #5871ad);
}
@media (max-width: 720px) {
.shop-offers-table,
.shop-offers-table thead,
.shop-offers-table tbody,
.shop-offers-table tr,
.shop-offers-table th,
.shop-offers-table td { display: block; }
.shop-offers-table thead { display: none; }
.shop-offers-table tr {
border-bottom: 1px solid var(--input-border, #e0e0e0);
padding: var(--space-2, 8px) 0;
}
.shop-offers-table td {
border: 0;
padding: var(--space-1, 4px) var(--space-3, 12px);
}
}
/* Render order on the edit page (CSS order property reorders without
changing HTML source order):
1. Edit Title, Description, or Visibility (full width, top)
2. Upload Product File (left column)
3. Upload Preview File (right column, sibling of Upload Product)
4. Upload Thumbnails (full width)
5. Price History (whatever comes last) */
div.edit-page > section.product-title-and-description { order: 1; }
div.edit-page > section.upload-product-and-preview { order: 2; }
div.edit-page > section.upload-preview { order: 3; }
div.edit-page > section.upload-thumbnails { order: 4; }
div.edit-page > section.price-history { order: 5; }
hr {
color: var(--border-light, #EEEEEE);
}
section.upload-product-and-preview {
}
/* Thumbnails section: header row above, thumbnail grid below.
(Grid only — no flex.) */
.upload-thumbnails-header {
display: grid;
grid-template-columns: 1fr auto;
align-items: start;
gap: var(--space-4, 16px);
}
@media (max-width: 600px) {
.upload-thumbnails-header {
grid-template-columns: 1fr;
}
}
.upload-thumbnails-header h3 {
margin: 0;
min-width: 0;
}
.upload-thumbnails-hint {
margin: 0;
color: var(--color-text-muted, #666);
text-align: right;
max-width: 320px;
}
.upload-thumbnails-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: var(--space-4, 16px);
margin-top: var(--space-4, 16px);
align-items: stretch;
}
/* Each thumbnail cell is itself a grid: content rows pinned to the
top, the upload form pinned to the bottom (align-content: space-between
replaces the flex margin-top: auto trick). */
.upload-thumbnails-grid .upload-thumbnail-item {
display: grid;
grid-auto-rows: min-content;
align-content: space-between;
gap: var(--space-2, 8px);
padding: var(--space-3, 12px);
background: var(--surface-dim, #f9f9fa);
border: 1px solid var(--color-border, #eee);
border-radius: var(--radius-md, 8px);
min-width: 0;
}
.upload-thumbnails-grid .upload-thumbnail-item .edit-media-preview {
width: 100%;
max-width: 100%;
height: 140px;
object-fit: contain;
background: var(--surface, #fff);
border-radius: var(--radius-sm, 4px);
}
.upload-thumbnails-grid .upload-thumbnail-item p.bold-text {
word-break: break-word;
margin: 0;
}
.upload-thumbnails-grid .upload-thumbnail-item hr {
display: none;
}
section.windows-95-task-bar {
display: grid;
grid-template-columns: 1fr;
grid-gap: 4px;
padding-top: 10px;
padding-bottom: 10px;
}
section.windows-95-start-button {
padding: 14px;
padding-top: 2px;
padding-bottom: 2px;
}
section.call-to-action {
padding: 14px;
padding-top: 2px;
padding-bottom: 2px;
}
section.one-column, section.one-column-thin {
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
section.one-column-thin {
max-width: 400px;
}
section.user-settings {
justify-self: right;
}
section.button-panel {
justify-self: left;
text-align: center;
}
section.existing-cards {
justify-self: right;
text-align: left;
margin-bottom: 40px;
}
section.new-card {
justify-self: left;
text-align: right;
margin-bottom: 40px;
}
div.card-details {
max-width: 240px;
margin:auto;
}
div.card-are-you-sure-buttons {
max-width: 300px;
margin:auto;
}
section.cart-left {
margin-bottom: 10px;
grid-column: 1 / span 3;
}
section.cart-left-grid {
display: grid;
grid-gap: 20px;
grid-template-columns: 1fr 4fr 1fr;
}
section.cart-right {
text-align: center;
margin-bottom: 10px;
grid-column: 4;
}
span.cart-left-item-title {
font-weight: bold;
font-size: 18px;
}
section.checkout-left {
justify-self: right;
text-align: left;
text-align: center;
margin-bottom: 40px;
}
section.checkout-right {
justify-self: left;
text-align: center;
margin-bottom: 40px;
}
/* Checkout page: responsive columns based on content */
section.checkout-page {
display: grid;
margin-left: auto;
margin-right: auto;
grid-gap: 20px;
max-width: 640px;
grid-template-columns: 1fr;
}
/* Two columns when multiple sections exist (Stripe + shipping) */
section.checkout-page .checkout-left + .checkout-right {
/* This targets checkout-right when it follows checkout-left */
}
section.checkout-page:has(.checkout-left) {
max-width: 1000px;
grid-template-columns: 1fr 1fr;
}
/* Fallback for browsers without :has() support */
@supports not (selector(:has(*))) {
section.checkout-page {
max-width: 1000px;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
}
}
section.checkout-page .well {
width: 100%;
box-sizing: border-box;
}
@media (max-width: 768px) {
section.checkout-page {
max-width: 100%;
margin: 0;
padding: 0 10px;
grid-template-columns: 1fr;
}
section.checkout-page:has(.checkout-left) {
grid-template-columns: 1fr;
}
}
.coupon {
/* Dotted border */
border-radius: var(--radius-sm, 4px);
border: 3px dotted var(--text-disabled, #bbb);
padding: var(--space-5, 20px);
}
#email2_input {
display: None;
}
.StripeElement {
width: 90%;
margin: auto;
border-color: var(--input-border, #bbbbbb);
border-style: solid;
border-width: 1px;
border-radius: var(--radius-md, 8px);
background-color: var(--surface-base, white);
padding: var(--space-3, 12px);
}
.opacity-60 {
opacity: .60;
}
.well, .well2 {
background-color: var(--surface-dim, #F9F9FA);
border-radius: var(--radius-md, 10px);
padding: 10px;
border: 1px solid transparent;
}
.well-green {
background-color: var(--green-color);
color: white;
}
/* Content card — material-style elevated panel for product page sections
(description, file info, comments). Subtle elevation-1 shadow + light
border gives clear layering against the page surface; generous padding
replaces the loose <br/><br/> separators these sections used to rely
on. Grid only — no flex. */
.content-card {
background-color: var(--surface-base, #FFFFFF);
border-radius: var(--radius-lg, 12px);
border: 1px solid var(--border-light, #eeeeee);
box-shadow: var(--elevation-1);
padding: var(--space-5, 20px);
margin-bottom: var(--space-4, 16px);
display: grid;
gap: var(--space-3, 12px);
/* min-width: 0 lets this grid item shrink below its content's
intrinsic width (default: auto). Without it, descriptions with
long links or unbreakable tokens push the card wider than the
viewport — and since .content has overflow-x: clip, the right
edge silently gets cut off instead of wrapping. */
min-width: 0;
max-width: 100%;
overflow-wrap: break-word;
}
.content-card-header {
margin: 0;
font-size: var(--text-sm, 0.875rem);
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--text-muted, #777);
min-width: 0;
overflow-wrap: break-word;
}
.content-card-body {
margin: 0;
min-width: 0;
overflow-wrap: break-word;
}
/* Long URLs / unbroken tokens inside rendered markdown still need to
wrap — break-word lets the browser hyphenate them at any character. */
.content-card-body a,
.content-card-body p,
.product-description a,
.product-description p {
overflow-wrap: break-word;
word-break: break-word;
}
.content-card-meta {
margin: 0;
color: var(--text-muted, #777);
font-size: var(--text-sm, 0.875rem);
}
[data-theme="dark"] .content-card {
background-color: var(--surface-container, #161b22);
border-color: var(--border-default, #30363d);
}
/* Comment form polish — applied inside .content-card so it inherits the
panel chrome. Stacked label / control / hint with proper spacing,
inputs and textarea fill the width consistently. Grid only. */
.comment-form {
display: grid;
gap: var(--space-3, 12px);
}
.comment-form h4 {
margin: 0;
font-size: var(--text-md, 1.125rem);
font-weight: 600;
}
.comment-form form {
display: grid;
gap: var(--space-3, 12px);
}
.comment-form-field {
display: grid;
gap: var(--space-1, 4px);
}
.comment-form label {
margin: 0;
font-weight: 600;
}
.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form textarea {
width: 100%;
box-sizing: border-box;
padding: var(--space-2, 8px) var(--space-3, 12px);
}
.comment-form textarea {
min-height: 6rem;
resize: vertical;
}
.comment-form .mps-comment-form-button {
justify-self: start;
padding: var(--space-2, 8px) var(--space-4, 16px);
}
/* Comments list polish — each comment is a soft inset surface within
the parent .content-card so the depth reads clearly. Replies inherit
the same chrome with a left accent. */
.comments-section { display: grid; gap: var(--space-4, 16px); }
.comments-section h3 { margin: 0; }
#comments-list { display: grid; gap: var(--space-3, 12px); }
.comments-section .comment {
background-color: var(--surface-dim, #f9f9fa);
border-radius: var(--radius-md, 8px);
padding: var(--space-3, 12px) var(--space-4, 16px);
/* The inline `style="margin-left: Npx"` on .comment in the snippet
gives nested replies a stair-step indent; keep that working but
drop the legacy 20px bottom-margin (we use grid gap above). */
margin-bottom: 0 !important;
}
.comments-section .comment-reply {
border-left: 3px solid var(--color-navy, #5871ad);
}
.comments-section .comment-header {
display: grid;
grid-template-columns: auto auto 1fr;
gap: var(--space-2, 8px);
align-items: baseline;
margin-bottom: var(--space-2, 8px);
}
.comments-section .comment-date {
color: var(--text-muted, #777);
font-size: var(--text-sm, 0.875rem);
}
.comments-section .comment-title {
font-weight: 600;
}
.comments-section .comment-content {
margin-bottom: var(--space-2, 8px);
}
/* Back-to-shop link on the product page: small secondary link below the
comments card, left-aligned, not stretched to the full row. */
.product-back-link {
margin-top: var(--space-3, 12px);
justify-self: start;
}
/* Saved-carts list (/u/carts). Each row is a small grid:
[summary | actions]
[products spans both]
Active rows get a green accent; checked-out rows get a navy accent
and surface the invoice line items so the user can re-purchase from
here. Grid only. */
.carts-list {
display: grid;
gap: var(--space-2, 8px);
}
.cart-row {
display: grid;
grid-template-columns: 1fr auto;
grid-template-areas:
"summary actions"
"products products";
align-items: start;
column-gap: var(--space-3, 12px);
row-gap: var(--space-2, 8px);
padding: var(--space-3, 12px);
border-radius: var(--radius-md, 8px);
background: var(--surface-dim, #f9f9fa);
}
.cart-row-summary {
grid-area: summary;
display: grid;
gap: var(--space-1, 4px);
}
.cart-row-actions {
grid-area: actions;
margin: 0;
display: grid;
grid-auto-flow: column;
gap: var(--space-2, 8px);
align-items: start;
}
.cart-row-action-form { margin: 0; }
.cart-row-products,
.cart-row-products-block { grid-area: products; }
.cart-row-active {
background: color-mix(in srgb, var(--color-green, #a3c765) 14%, var(--surface-base, #fff) 86%);
border-left: 3px solid var(--color-green, #a3c765);
padding-left: calc(var(--space-3, 12px) - 3px);
}
.cart-row-checked-out {
background: color-mix(in srgb, var(--color-navy, #5871ad) 10%, var(--surface-base, #fff) 90%);
border-left: 3px solid var(--color-navy, #5871ad);
padding-left: calc(var(--space-3, 12px) - 3px);
}
.cart-row-link { font-weight: 600; text-decoration: none; }
.cart-row-meta {
color: var(--text-muted, #777);
font-size: var(--text-sm, 0.875rem);
}
.cart-row-tag {
text-transform: uppercase;
font-size: var(--text-xs, 0.75rem);
letter-spacing: 0.04em;
}
.cart-row-tag-active { color: var(--color-green, #4d7a1f); }
.cart-row-tag-checked-out { color: var(--color-navy, #5871ad); }
.cart-row-products {
margin: 0;
padding-left: var(--space-5, 20px);
display: grid;
gap: var(--space-1, 4px);
font-size: var(--text-sm, 0.875rem);
}
.cart-row-products-block {
display: grid;
gap: var(--space-2, 8px);
justify-items: start;
}
.cart-row-receipt { justify-self: start; }
.cart-row-activate {
background: var(--color-green, #a3c765);
color: #fff;
border: 1px solid var(--color-green, #a3c765);
}
.cart-row-activate:hover { filter: brightness(1.05); }
.cart-row-delete {
background: var(--color-danger, #CC6958);
color: #fff;
border: 1px solid var(--color-danger, #CC6958);
}
.cart-row-delete:hover { filter: brightness(1.05); }
@media (max-width: 600px) {
.cart-row {
grid-template-columns: 1fr;
grid-template-areas:
"summary"
"products"
"actions";
}
.cart-row-actions { justify-self: end; }
}
[data-theme="dark"] .one-column.well.well-green,
[data-theme="dark"] .action-columns.well.well-green {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green.png");
border: 2px solid var(--green-color);
box-shadow: 0 0 10px rgba(163, 199, 101, 0.3);
color: white;
}
[data-theme="dark"] .well-green .shop-new-button {
background-image: url("/static/img/trans-green.png");
}
/* Action hub (actions_view.j2): one flat list of operator-shortcut
buttons that auto-flows into AT MOST two equal columns (single column
on narrow viewports). Grid only — no flex, no <br> spacers.
`.mps-button` defaults to `min-width: 100%` + auto margins which fights
grid track sizing and eats the gap, so we reset those on grid items. */
.action-columns {
display: grid;
max-width: 760px;
margin: 0 auto;
padding: var(--space-5, 20px);
}
.action-button-grid {
display: grid;
grid-template-columns: 1fr;
column-gap: var(--space-4, 16px);
row-gap: var(--space-3, 12px);
align-content: start;
}
@media (min-width: 720px) {
.action-button-grid {
grid-template-columns: 1fr 1fr;
}
}
.action-button-grid .mps-button {
min-width: 0;
width: 100%;
box-sizing: border-box;
margin: 0;
}
/* markup editor css */
section.markup-settings {
width: 100%;
min-height: 280px;
}
textarea.markup-editor-textarea {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
height: 400px;
}
.markup-editor-submit {
float: right;
}
.markup-preview-div {
width: 100%;
}
.markup-preview-div {
border-top: 1px dotted var(--text-disabled, #bbbbbb);
border-bottom: 1px dotted var(--text-disabled, #bbbbbb);
padding-top: 16px;
padding-bottom: 16px;
margin-top: 16px;
margin-bottom: 16px;
margin-right: 5px;
margin-left: 5px;
line-height: 1.6;
}
.markup-preview-div p {
margin-top: 15px;
margin-bottom: 15px;
line-height: 1.75;
}
.preview-raw-markup {
display: block;
white-space: pre-wrap;
background-color: unset;
border-radius: unset;
border: unset;
border-width: 0px;
margin-top: 19px;
margin-bottom: 10px;
}
.discounted {
color: var(--color-green, #a3c765);
}
/* Use 959px (one below the desktop two-column breakpoint at 960px) so
tablet portrait + small-laptop widths get the same hoisted-CTA stack
as phone — without it, viewports in the 800-959 gap fall to source
order and the buy zone sinks below comments again. */
@media (max-width: 959px) {
/* the two-column is stacked by default. */
section.two-column {
display: grid;
grid-template-columns: 1fr;
margin-left: auto;
margin-right: auto;
padding-left: 4px;
padding-right: 4px;
}
/* Section order on tablet + phone: the buy zone (price + Add To
Cart + preview / auction / offer buttons) is hoisted ABOVE the
title — that title lives inside .product-images, so order:0 on
.product-purchase lifts the well above the entire image block.
Related content (comments link, price history, related products)
falls to the bottom so it doesn't push the title off-screen. */
section.product-purchase {
order: 0;
width: 100%;
}
section.product-purchase .well {
margin-top: var(--space-2, 8px);
margin-bottom: var(--space-3, 12px);
}
.product-images {
order: 1;
max-width: 100%;
overflow: hidden;
min-width: 0;
}
.product-images img.product-main {
max-width: 100%;
max-height: 42vh;
width: auto;
height: auto;
}
.product-description {
order: 2;
}
.product-comments {
order: 3;
}
section.product-related {
order: 4;
width: 100%;
}
/* Watch mode mobile: dissolve watch-left wrapper so sticky video sticks
against the full grid container, not just the watch-left box */
.watch-left {
display: contents;
}
.watch-mode .product-images {
position: sticky;
top: 0;
z-index: 20;
background: var(--bg-primary, #ffffff);
}
.watch-mode .product-description,
.watch-mode .product-comments,
.watch-mode section.product-purchase,
.watch-mode section.product-related {
position: relative;
z-index: 5;
background: var(--bg-primary, #ffffff);
}
.watch-mode section.product-purchase { order: 0; }
.watch-mode section.product-related { order: 4; }
/* On mobile, show only 7 next items in related content */
.related-content-row.related-content-overflow {
display: none;
}
/* Fresh mode: show overflow items that aren't watched */
.related-content.fresh-mode .related-content-row.related-content-overflow:not(.related-content-row-watched) {
display: block;
}
/* Show the comments anchor link on mobile */
.related-content-comments-link,
.product-comments-link {
display: block;
text-align: center;
padding: 10px;
color: var(--blue-color, #5871ad);
font-weight: bold;
}
/* Ensure buttons get full width on mobile */
section.product-right .mps-button {
width: 100%;
min-width: 100%;
}
}
/* Mobile-only readability constraint: keep the single-column stack from
stretching edge-to-edge on phones. Tablet (800-959) intentionally
skips this so its wider viewport isn't pinned to a 600px column. */
@media (max-width: 800px) {
section.two-column {
max-width: 600px;
}
}
@media (max-width: 800px) {
/* the cart-grid is stacked by default. */
section.cart-grid {
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
/* markup-editor is stacked by default. */
div.markup-editor {
display: grid;
margin-left: auto;
margin-right: auto;
}
section.markup-rendered {
display: none;
}
}
/* cinema-content-stack is a template wrapper around description +
comments. Default display:contents makes it transparent so every
layout outside cinema mode sees children as direct grid items.
Cinema mode turns it into a single grid cell (rules below) so the
purchase column can't stretch description's row. */
.cinema-content-stack {
display: contents;
}
/* Cinema mode applies only at >=800px. Below that, mobile watch-mode
layout already gives you full-viewport-width media + stacked sections
(images, purchase, description, comments), so cinema would just
re-order things for no visual gain and break consistency with the
normal mode on the same device. Fox: "mobile really doesn't need
cinema mode" — we respect that by making cinema a no-op on mobile. */
@media (min-width: 800px) {
section.two-column.cinema-mode.cinema-wide {
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-areas:
"images images"
"content purchase"
"content related";
gap: 24px;
max-width: 100%;
padding-left: 20px;
padding-right: 20px;
align-items: start;
}
section.two-column.cinema-mode.cinema-wide .watch-left {
display: contents;
}
section.two-column.cinema-mode.cinema-wide .cinema-content-stack {
display: grid;
grid-area: content;
grid-template-rows: auto auto;
gap: 16px;
align-content: start;
min-width: 0;
}
section.two-column.cinema-mode.cinema-wide .product-images { grid-area: images; }
section.two-column.cinema-mode.cinema-wide section.product-purchase { grid-area: purchase; align-self: start; }
section.two-column.cinema-mode.cinema-wide section.product-related { grid-area: related; align-self: start; }
section.two-column.cinema-mode.cinema-wide .watch-video-container {
max-height: 92vh;
}
/* Cinema video/cover fills horizontal space. Intentional override
of the CLAUDE.md media-sizing rule — cinema wants edge-to-edge
even if viewport aspect ratio forces a little letterbox.
object-fit:contain keeps aspect ratio safe. */
section.two-column.cinema-mode.cinema-wide .product-main,
section.two-column.cinema-mode.cinema-wide .watch-video-container > video,
section.two-column.cinema-mode.cinema-wide .watch-audio-container > .product-main {
width: 100%;
height: auto;
max-width: 100%;
max-height: 92vh;
object-fit: contain;
display: block;
margin-left: auto;
margin-right: auto;
}
/* Cinema: the main media is already showing at full viewport width,
so the wrapping "click to open in new window" link is redundant
and just steals the click from scrolling and other interactions. */
section.two-column.cinema-mode.cinema-wide .product-images > a[target="_blank"] {
pointer-events: none;
cursor: default;
}
/* Cinema: task bar (hamburger + Edit) relocates into .product-right
above the well via JS. Stack its children vertically and make it
feel like part of the sidebar rather than a floating chrome strip. */
section.two-column.cinema-mode.cinema-wide section.product-right section.windows-95-task-bar {
grid-template-columns: 1fr;
padding: 0;
margin-bottom: 8px;
grid-gap: 8px;
}
section.two-column.cinema-mode.cinema-wide section.product-right section.windows-95-start-button,
section.two-column.cinema-mode.cinema-wide section.product-right section.call-to-action {
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
}
/* Uniform button shape in the cinema sidebar — hamburger, Edit, and
Download all read as the same component: full column width, same
padding, same type, same line height. Override the mps-button-small
shrink on Edit so it matches its siblings instead of looking like
a leftover chip. */
section.two-column.cinema-mode.cinema-wide section.product-right a.mps-button,
section.two-column.cinema-mode.cinema-wide section.product-right button.mps-button {
display: block;
width: 100%;
min-width: 0;
box-sizing: border-box;
padding: 14px 16px;
margin-top: 0;
margin-bottom: 8px;
font-size: var(--text-sm, 14px);
line-height: 1.3;
white-space: normal;
text-align: center;
}
/* Separate the comment section from the description block above and
the sidebar controls below so it reads as its own area, not just
more lines of text glued to the toolbar. */
section.two-column.cinema-mode.cinema-wide .product-comments {
margin-top: 24px;
padding-top: 20px;
border-top: 1px solid var(--border-color, #ccc);
}
}
/*************************************************************
*
* for displays bigger than 800px which are "desktop-ish".
*
*************************************************************/
@media (min-width: 960px) {
/* The SERP page grid should have bigger items since it has more room.
* mobile -> desktop
* 160px -> 240px */
section.serp {
grid-template-columns: repeat(auto-fit, minmax(240px, .25fr));
}
/* We have the room to really break into 2 columns. The purchase
column has a 280px floor so the price/Add-To-Cart/offer box never
gets crushed on mid-width viewports (960px1200px). */
section.two-column {
display: grid;
grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
grid-template-areas:
"images purchase"
"description related"
"comments related";
gap: 40px;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
padding-left: 40px;
padding-right: 40px;
align-items: start;
}
.product-images {
grid-area: images;
}
section.product-purchase {
grid-area: purchase;
}
section.product-related {
grid-area: related;
}
.product-description {
grid-area: description;
}
.product-comments {
grid-area: comments;
}
/* Watch mode: two-column layout with left wrapper for sticky video.
Right column stacks purchase (top) and related (below). */
section.two-column.watch-mode {
grid-template-columns: 2fr 1fr;
grid-template-areas:
"left purchase"
"left related";
align-items: stretch;
}
.watch-left {
grid-area: left;
min-width: 0;
}
/* In watch mode, child divs inside watch-left are plain block elements */
.watch-mode .product-images,
.watch-mode .product-description,
.watch-mode .product-comments {
grid-area: auto;
}
/* Desktop watch mode: content scrolls under sticky video */
.watch-mode .product-description,
.watch-mode .product-comments {
position: relative;
z-index: 5;
background: var(--bg-primary, #ffffff);
}
.watch-mode section.product-purchase,
.watch-mode section.product-related {
align-self: start;
}
/* if we have room, break markup-editor into 2 columns */
div.markup-editor {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-columns: max-content;
grid-auto-flow: dense;
grid-gap: 30px;
padding: 14px;
justify-items: center;
}
section.markup-settings {
min-height: 400px;
}
/* the minimum width for "desktop-ish" screens. */
a.mps-button {
min-width: 280px;
}
/* really make the button small now that we have room. */
a.mps-button-small {
min-width: 140px;
padding-left: 10px;
padding-right: 10px;
}
section.windows-95-task-bar {
grid-template-columns: 1fr 1fr;
}
section.call-to-action {
text-align: right;
}
/* if we have room, break into 2 columns */
section.cart-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 30px;
padding: 14px;
justify-items: center;
}
img.product-cart-thumbnail {
max-width:104px;
max-height:104px;
}
section.content {
background-color: var(--surface-base, #ffffff);
margin: 4px;
padding-bottom: 42px;
}
input.mps-keywords {
text-align: left;
}
section.nav {
/* if we have room, break navbar into 3 columns */
grid-template-columns: minmax(200px, 300px) 3fr 1fr;
grid-gap: 30px;
padding: 2px;
}
div.message-ribbon {
display: grid;
}
/* Desktop, NOT watch mode: full nav is sticky */
body:not(.watch-mode-shop) section.nav {
position: sticky;
top: 0;
z-index: 40;
}
/* Desktop, watch mode: ribbon + logo stick, rest of nav scrolls */
.watch-mode-shop div.message-ribbon {
position: sticky;
top: 0;
z-index: 40;
}
.watch-mode-shop section.logo {
position: sticky;
top: 0;
z-index: 39;
background-color: var(--bg-secondary);
}
/* Desktop: offset sticky video below the sticky ribbon */
.watch-mode .product-images {
top: 42px;
}
section.log-in {
text-align: right;
}
.well, .well2 {
padding: 10px;
padding-right: 20px;
padding-left: 20px;
}
.well2 {
padding: 10px;
}
}
@media (min-width: 1200px) {
img.product-cart-thumbnail {
max-width:184px;
max-height:184px;
}
.well, .well2 {
padding: 20px;
padding-right: 40px;
padding-left: 40px;
}
.well2 {
padding: 20px;
}
}
/*
* Desktop: Progressive enhancement for CSS Grid Lanes
* This uses nested @supports inside @media to only apply when both
* the viewport is desktop-sized AND the browser supports grid-lanes
* AND the shop has grid-lanes-enabled class set
*/
@media (min-width: 960px) {
@supports (display: grid-lanes) {
section.serp.grid-lanes-enabled {
display: grid-lanes;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 4px;
item-tolerance: 1em;
}
}
}
div.message-ribbon {
color: var(--text-inverse, #ffffff);
background-color: var(--color-navy, #5871ad);
background: linear-gradient(to right, var(--color-navy, #5871ad), var(--color-navy-light, #82A8FF));
}
.highlight {
text-shadow:
-6px 0px 6px rgba(255, 231, 13, 0.6),
6px 0px 6px rgba(255, 231, 13, 0.6),
12px 0px 12px rgba(255, 231, 13, 0.6),
-12px 0px 12px rgba(255, 231, 13, 0.6);
}
.avoid-wrap {
display:inline-block;
}
.vertical-text {
display: inline-block;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.shown-on-desktop {
display: none;
}
.not-shown-on-desktop {
display: block;
}
@media screen and (min-width:800px) {
.shown-on-desktop {display: block}
.not-shown-on-desktop {display: none}
}
div.message-ribbon {
color: var(--text-inverse, #ffffff);
background-color: var(--color-navy, #5871ad);
background: linear-gradient(to right, var(--color-navy, #5871ad), var(--color-navy-light, #82A8FF));
}
#alerts {
animation: fadein 2s;
}
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
/* ALERT START */
#alerts {
z-index: 98;
}
.alert {
opacity: .85;
display: grid;
grid-template-columns: 1fr 50px;
grid-gap: 10px;
font-weight: bold;
}
.alert-message {
text-align: center;
margin-top: 10px;
margin-bottom: 10px;
}
.alert .close {
text-align: right;
margin-top: 10px;
margin-bottom: 10px;
margin-right: 15px;
}
.alert-danger, .alert-error {
color: var(--alert-danger-text, #721c24);
background-color: var(--alert-danger-bg, #f8d7da);
border: 1px solid var(--alert-danger-border, #f5c6cb);
}
.alert-warning {
color: var(--alert-warning-text, #856404);
background-color: var(--alert-warning-bg, #fff3cd);
border: 1px solid var(--alert-warning-border, #ffeeba);
}
.alert-info, .alert-notice {
color: var(--text-primary);
background-color: color-mix(in srgb, var(--info-color) 20%, var(--bg-primary) 80%);
border: 1px solid var(--info-color);
}
.alert-success {
color: var(--alert-success-text, #155724);
background-color: var(--color-green, #a3c765);
border: 1px solid var(--alert-success-border, #c3e6cb);
}
/* ALERT END */
/* Pure CSS toggle using <details> element */
.toggle-summary {
cursor: pointer;
list-style: none;
color: var(--primary-color);
text-decoration: underline;
}
.toggle-summary::-webkit-details-marker {
display: none;
}
.toggle-summary::marker {
display: none;
content: "";
}
.api-key-details {
margin-top: 10px;
}
.api-key-fields {
margin-top: 10px;
}
/* Status and message styling */
.status-message {
color: var(--text-secondary, #666);
}
.success-indicator {
color: green;
}
.error-indicator {
color: #d44;
}
.note-text {
color: var(--text-secondary, #666);
}
[data-theme="dark"] .note-text {
color: #c0c0c0;
}
[data-theme="dark"] .status-message {
color: #c0c0c0;
}
[data-theme="dark"] .error-indicator {
color: #ff6b6b;
font-weight: bold;
}
/* Flash message styling for dark mode */
[data-theme="dark"] .alert-danger,
[data-theme="dark"] .alert-error {
color: white;
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red2.png");
border-color: var(--red-color);
}
[data-theme="dark"] .alert-warning {
color: white;
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-red2.png");
border-color: #ffd93d;
}
[data-theme="dark"] .alert-info,
[data-theme="dark"] .alert-notice {
color: white;
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue2.png");
border-color: var(--blue-color);
}
[data-theme="dark"] .alert-success {
color: white;
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-green2.png");
border-color: var(--green-color);
}
/* Override shop theme link colors to ensure visibility in dark mode */
[data-theme="dark"] a.shop-theme-link-color,
[data-theme="dark"] .shop-theme-link-color {
color: #ffffff !important;
}
/* User settings page grid layout */
.user-settings-grid {
display: grid;
grid-template-columns: 1fr;
gap: 20px;
}
@media (min-width: 960px) {
.user-settings-grid {
grid-template-columns: 1fr 1fr;
gap: 40px;
}
}
/* Add payment method button styling */
.add-payment-method-button {
background-color: var(--blue-color);
color: white;
text-decoration: none;
}
.add-payment-method-button:hover {
background-color: #4a90e2;
color: white;
}
[data-theme="dark"] .add-payment-method-button {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue.png");
color: var(--blue-color);
border: 2px solid var(--blue-color);
}
[data-theme="dark"] .add-payment-method-button:hover {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue2.png");
color: #ffffff;
border: 2px solid var(--blue-color);
}
.inline-label {
display: inline;
}
.favicon-preview {
width: 32px;
}
/* Input field styling */
.full-width-input {
width: 100%;
}
.disabled-input {
opacity: 0.5;
background-color: var(--surface-container, #f5f5f5);
}
/* Crypto checkout styles */
.crypto-logo {
width: 150px;
height: 150px;
margin-right: 15px;
vertical-align: middle;
}
.payment-grid {
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
margin: 16px 0;
align-items: start;
}
.crypto-address {
white-space: pre-wrap;
word-wrap: break-word;
}
.payment-buttons {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 8px;
margin: 8px 0;
}
.payment-button-row-1 {
grid-row: 1;
}
.payment-button-cancel {
grid-column: 1 / -1;
grid-row: 2;
}
.status-box {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
color: var(--text-primary);
border-radius: 4px;
padding: 15px;
margin: 10px 0;
}
.confirmations-hidden {
display: none;
}
.qr-fallback {
width: 150px;
height: 150px;
background: var(--surface-container, #f0f0f0);
display: grid;
place-items: center;
font-size: var(--text-xs, 12px);
color: var(--text-secondary, #666);
border: 1px solid var(--border-default, #ddd);
}
.success-notice {
background: color-mix(in srgb, var(--success-color) 15%, var(--bg-primary) 85%);
border: 1px solid var(--success-color);
color: var(--text-primary);
border-radius: 4px;
padding: 15px;
margin: 20px 0;
}
.warning-notice {
background: color-mix(in srgb, var(--warning-color) 15%, var(--bg-primary) 85%);
border: 1px solid var(--warning-color);
color: var(--text-primary);
border-radius: 4px;
padding: 15px;
margin: 20px 0;
}
.monospace-address {
font-family: var(--font-mono, monospace);
background: var(--bg-secondary);
color: var(--text-primary);
padding: 8px;
border-radius: 3px;
word-break: break-all;
}
.notice-list {
margin: 10px 0;
}
.notice-footer {
margin-top: 10px;
}
/* Cart checkout styles */
.disabled-crypto-button {
background: #aaa !important;
cursor: not-allowed;
}
[data-theme="dark"] .disabled-crypto-button {
background-color: #1a1a1a !important;
background-image: none !important;
color: #666666 !important;
border: 2px solid #444444 !important;
cursor: not-allowed;
opacity: 0.6;
}
button img.crypto-button-icon,
.mps-button img.crypto-button-icon,
img.crypto-button-icon {
width: 32px !important;
height: 32px !important;
max-width: 32px !important;
min-width: 32px !important;
margin-right: 8px;
vertical-align: middle;
}
.crypto-settings-link {
color: #f59e0b;
text-decoration: none;
display: block;
margin-top: 10px;
font-size: 14px;
}
.warning-banner {
background: var(--alert-warning-bg, #fff3cd);
border: 1px solid var(--alert-warning-border, #ffeaa7);
padding: 10px;
border-radius: var(--radius-sm, 5px);
color: var(--alert-warning-text, #856404);
}
.warning-banner-alt {
background: color-mix(in srgb, var(--info-color) 15%, var(--bg-primary) 85%);
border: 1px solid var(--info-color);
color: var(--text-primary);
border-radius: 4px;
padding: 15px;
margin: 20px 0;
}
.warning-banner p {
margin: 0;
font-size: 14px;
}
.warning-banner h3 {
margin-top: 0;
}
.warning-banner-content {
margin-bottom: 15px;
}
.pending-quote-item {
background: transparent;
border: none;
color: var(--text-primary);
border-radius: 3px;
padding: 10px;
margin: 8px 0;
}
.pending-quote-single {
text-align: center;
}
.pending-quote-cancel {
text-align: center;
margin-top: 10px;
}
.full-width-button {
width: 100%;
display: block;
}
.view-quote-button {
background: #17a2b8;
font-size: 12px;
padding: 5px 10px;
}
.pending-quote-details {
font-size: var(--text-xs, 12px);
color: var(--text-secondary, #666);
margin-top: 5px;
}
/* Cart page styles */
.cart-float-right {
float: right;
}
.cart-shop-grid-span {
grid-column: span 3;
}
.cart-shop-name {
font-size: 1.5em;
font-weight: bold;
}
.cart-inline-form {
display: inline;
}
.cart-update-button {
width: 80px;
}
.cart-total-section {
text-align: right;
}
.cart-total-grid-span {
text-align: right;
grid-column: span 3;
}
.cart-total-amount {
font-size: 1.5em;
font-weight: bold;
}
.cart-public-link {
font-size: 0.8em;
}
/* ====================================================================
MPS-20 + MPS-21 — cart negotiation card (offer accepted / auction won)
Highlights an agreed price over the line-item list price so the buyer
sees the deal they negotiated. Pure CSS Grid, design tokens only.
==================================================================== */
.cart-negotiation-card {
background: var(--alert-success-bg, #e8f5d4);
border: 1px solid var(--alert-success-border, #c3e6cb);
border-left: 4px solid var(--color-green-dark, #8ab34e);
border-radius: var(--radius-lg, 12px);
padding: var(--space-5, 20px) var(--space-6, 24px);
}
.cart-negotiation-grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-4, 16px);
}
@media (min-width: 720px) {
.cart-negotiation-grid {
grid-template-columns: 1fr auto;
align-items: center;
column-gap: var(--space-8, 32px);
}
.cart-negotiation-footer {
grid-column: 1 / -1;
}
}
.cart-negotiation-eyebrow {
display: inline-block;
font-size: var(--text-xs, 0.75rem);
font-weight: var(--weight-bold, 700);
text-transform: uppercase;
letter-spacing: var(--tracking-wider, 0.05em);
color: var(--color-green-dark, #8ab34e);
margin-bottom: var(--space-1, 4px);
}
.cart-negotiation-title {
font-size: var(--text-xl, 1.5rem);
font-weight: var(--weight-bold, 700);
line-height: var(--leading-tight, 1.15);
color: var(--text-primary, #0b0b0b);
margin: 0;
}
.cart-negotiation-product {
margin: var(--space-1, 4px) 0 0 0;
color: var(--text-body, #515151);
font-size: var(--text-sm, 0.875rem);
}
.cart-negotiation-numbers {
display: grid;
grid-template-columns: auto auto;
column-gap: var(--space-5, 20px);
row-gap: var(--space-1, 4px);
margin: 0;
justify-content: end;
}
.cart-negotiation-row {
display: contents;
}
.cart-negotiation-numbers dt {
font-size: var(--text-sm, 0.875rem);
color: var(--text-secondary, #666);
text-align: left;
margin: 0;
}
.cart-negotiation-numbers dd {
font-size: var(--text-sm, 0.875rem);
color: var(--text-secondary, #666);
text-align: right;
margin: 0;
font-variant-numeric: tabular-nums;
}
.cart-negotiation-agreed {
font-size: var(--text-xl, 1.5rem);
font-weight: var(--weight-bold, 700);
color: var(--color-green-dark, #8ab34e);
line-height: var(--leading-tight, 1.15);
}
.cart-negotiation-savings-row dt,
.cart-negotiation-savings-row dd {
padding-top: var(--space-2, 8px);
border-top: 1px dashed var(--alert-success-border, #c3e6cb);
}
.cart-negotiation-savings {
color: var(--color-green-dark, #8ab34e);
font-weight: var(--weight-bold, 700);
}
/* Buyer's accepted-offer pay panel — Cancel on the left, Pay on the
right, side-by-side on desktop, stacked on narrow viewports. Pay
gets the visual weight (green primary), Cancel reads as the
less-emphasized option. Grid only — no flex. */
.offer-pay-cta-actions {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-3, 12px);
}
.offer-pay-cta-actions form {
margin: 0;
}
.offer-pay-cta-actions form:last-child {
justify-self: end;
}
@media (max-width: 600px) {
.offer-pay-cta-actions {
grid-template-columns: 1fr;
}
.offer-pay-cta-actions form:last-child {
justify-self: stretch;
}
}
/* Notification badge near the profile name + the /u/notifications list. */
.notification-badge {
display: inline-grid;
place-items: center;
min-width: 1.5em;
padding: 0 var(--space-2, 8px);
margin-left: var(--space-1, 4px);
background: var(--color-danger, #CC6958);
color: var(--text-inverse, #fff);
border-radius: var(--radius-full, 9999px);
font-size: var(--text-xs, 0.75rem);
font-weight: var(--weight-bold, 700);
line-height: 1.6;
}
.notifications-page .notifications-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: var(--space-4, 16px);
}
.notification-row {
display: grid;
gap: var(--space-1, 4px);
padding: var(--space-3, 12px);
border-radius: var(--radius-md, 8px);
background: var(--surface-dim, #f9f9fa);
/* Read rows stay in the list but fade — fox's call: don't delete
them, just make unread visually dominant. */
opacity: 0.65;
}
.notification-row-unread {
background: var(--alert-info-bg, #dce8ff);
border-left: 4px solid var(--color-navy, #5871ad);
opacity: 1;
}
.notification-row-header {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: var(--space-2, 8px);
}
.notification-row-kind {
font-size: var(--text-xs, 0.75rem);
font-weight: var(--weight-bold, 700);
text-transform: uppercase;
letter-spacing: var(--tracking-wider, 0.05em);
color: var(--text-secondary, #666);
}
.notification-row-when {
font-size: var(--text-xs, 0.75rem);
color: var(--text-faint, #999);
font-variant-numeric: tabular-nums;
}
.notification-row-subject {
font-weight: var(--weight-bold, 700);
text-decoration: none;
}
.notification-row-body {
margin: 0;
color: var(--text-body, #515151);
font-size: var(--text-sm, 0.875rem);
}
.notification-row-breadcrumbs {
margin-top: var(--space-1, 4px);
font-size: var(--text-xs, 0.75rem);
color: var(--text-secondary, #666);
}
.notification-row-dismiss-form {
margin-top: var(--space-1, 4px);
justify-self: end;
}
.product-add-disabled-note {
margin: var(--space-2, 8px) 0 0 0;
font-size: var(--text-sm, 0.875rem);
color: var(--text-secondary, #666);
max-width: 30em;
}
.cart-negotiation-deadline {
grid-column: 1 / -1;
margin: var(--space-3, 12px) 0 0 0;
padding-top: var(--space-3, 12px);
border-top: 1px dashed var(--alert-success-border, #c3e6cb);
font-size: var(--text-sm, 0.875rem);
color: var(--text-body, #515151);
}
.cart-negotiation-deadline strong {
color: var(--color-green-dark, #8ab34e);
font-variant-numeric: tabular-nums;
}
.cart-negotiation-footer {
text-align: right;
}
.cart-negotiation-link {
font-size: var(--text-sm, 0.875rem);
text-decoration: none;
}
.cart-negotiation-link:hover {
text-decoration: underline;
}
.cart-negotiation-pill {
display: inline-grid;
place-items: center;
grid-auto-flow: column;
background: var(--alert-success-bg, #e8f5d4);
color: var(--color-green-dark, #8ab34e);
border: 1px solid var(--alert-success-border, #c3e6cb);
border-radius: var(--radius-full, 9999px);
padding: var(--space-1, 4px) var(--space-3, 12px);
font-size: var(--text-xs, 0.75rem);
font-weight: var(--weight-bold, 700);
letter-spacing: var(--tracking-wide, 0.02em);
text-transform: uppercase;
}
.cart-total-savings-note {
margin: var(--space-2, 8px) 0 var(--space-3, 12px) 0;
font-size: var(--text-sm, 0.875rem);
color: var(--text-secondary, #666);
}
.cart-total-savings-note s {
color: var(--text-faint, #999);
}
.cart-total-savings-note b {
color: var(--color-green-dark, #8ab34e);
}
/* ====================================================================
/billing — card + PayPal management page.
==================================================================== */
.billing-page {
display: grid;
gap: var(--space-5, 20px);
max-width: 1000px;
margin-left: auto;
margin-right: auto;
padding: 0 var(--space-3, 12px);
}
.billing-cards-grid {
align-items: start;
}
.billing-meta {
color: var(--text-secondary, #666);
margin: 0 0 var(--space-3, 12px) 0;
}
.billing-divider {
border: 0;
border-top: 1px solid var(--border-light, #eeeeee);
margin: var(--space-5, 20px) 0;
}
.billing-paypal-well {
/* Full-width below the cards grid. */
}
.billing-paypal-card {
display: grid;
gap: var(--space-3, 12px);
background: var(--alert-info-bg, #dce8ff);
border-left: 4px solid #0070ba;
border-radius: var(--radius-md, 8px);
padding: var(--space-4, 16px);
}
.billing-paypal-header {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-2, 8px);
color: #0070ba;
}
.billing-paypal-logo {
display: block;
}
.billing-inline-form {
margin: 0;
}
.billing-actions {
display: grid;
grid-template-columns: auto auto;
justify-content: center;
gap: var(--space-4, 16px);
margin: 0;
}
/* PayPal checkout: saved banner, save-for-next-time toggle, manage note. */
.cart-paypal-saved-banner {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-2, 8px);
background: var(--alert-info-bg, #dce8ff);
border-left: 4px solid #0070ba;
border-radius: var(--radius-md, 8px);
padding: var(--space-3, 12px);
margin-bottom: var(--space-3, 12px);
}
.cart-paypal-saved-check {
font-size: var(--text-lg, 1.25rem);
color: #0070ba;
}
.cart-paypal-saved-text {
font-weight: var(--weight-medium, 500);
color: #0070ba;
}
.cart-paypal-save-row {
margin-top: var(--space-3, 12px);
}
.cart-paypal-save-label {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-2, 8px);
cursor: pointer;
font-size: var(--text-sm, 0.875rem);
color: var(--text-body, #515151);
}
.cart-paypal-save-label input[type="checkbox"] {
cursor: pointer;
margin: 0;
}
.cart-paypal-manage-note {
margin: var(--space-5, 20px) 0 0 0;
font-size: var(--text-sm, 0.875rem);
color: var(--text-secondary, #666);
text-align: center;
}
@media (max-width: 640px) {
.billing-actions {
grid-template-columns: 1fr;
justify-content: stretch;
}
}
/* Phase 1: Static inline style replacements */
.no-bottom-margin {
margin-bottom: 0px;
}
.no-top-margin {
margin-top: 0px;
}
.bold-text {
font-weight: bold;
}
.stripe-card-logo {
width: 92px;
float: left;
margin-right: 10px;
margin-top: 10px;
}
.stripe-negative-margin {
margin-top: -12px;
}
.stripe-initial-width {
width: initial;
}
.stripe-save-button {
margin-bottom: 0px;
margin-top: 8px;
}
.comment-pending {
color: orange;
}
.hidden-form {
display: none;
}
.coupon-disabled {
opacity: 0.7;
}
.vertical-coupon-text {
margin: 0px;
}
.remove-button-small {
width: 80px;
}
.subtitle-text {
font-size: 0.45em;
font-weight: normal;
}
.product-meta-dates {
color: var(--text-muted);
font-size: 0.8em;
margin-top: 20px;
}
.original-comment-box {
background-color: var(--surface-container, #f5f5f5);
padding: 15px;
border-left: 4px solid var(--color-navy, #007cba);
margin-bottom: var(--space-5, 20px);
}
[data-theme="dark"] .original-comment-box {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue.png");
border-left: 4px solid var(--blue-color);
color: var(--text-primary);
}
/* Comment reply styling */
.comment-reply {
margin-left: 0px;
margin-bottom: var(--space-5, 20px);
border-left: 2px solid var(--border-default, #ddd);
padding-left: var(--space-3, 10px);
}
[data-theme="dark"] .comment-reply {
border-left: 2px solid var(--blue-color);
}
.start-button-icon {
font-size: 20px;
}
.table-full-width {
width: 100%;
max-width: 100%;
}
.table-fixed-layout {
table-layout: fixed;
}
.sold-out-button {
background-color: red !important;
cursor: not-allowed;
}
/* Phase 2: Static layout and status styling */
/* Crypto history layout classes */
.crypto-history-container {
margin: 20px 0;
}
.crypto-payment-card {
border: 1px solid var(--border-default, #dee2e6);
border-radius: var(--radius-sm, 4px);
padding: 15px;
margin-bottom: 15px;
background: var(--surface-dim, #f8f9fa);
}
.crypto-header-grid {
display: grid;
grid-template-columns: 1fr auto;
align-items: start;
margin-bottom: 10px;
}
.crypto-header-title {
margin: 0 0 5px 0;
}
.crypto-header-subtitle {
margin: 0;
color: var(--text-secondary, #6c757d);
font-size: 0.9em;
}
.crypto-details-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 15px;
margin: 10px 0;
align-items: start;
}
.crypto-right-align {
text-align: right;
}
.crypto-right-align-justify {
text-align: right;
justify-self: end;
}
.crypto-small-text {
color: var(--text-secondary, #6c757d);
}
/* Status notice classes */
.status-warning-notice {
background: var(--alert-warning-bg, #fff3cd);
border: 1px solid var(--alert-warning-border, #ffeaa7);
border-radius: var(--radius-sm, 3px);
padding: var(--space-2, 8px);
margin-top: var(--space-3, 10px);
}
.status-error-notice {
background: var(--alert-danger-bg, #f8d7da);
border: 1px solid var(--alert-danger-border, #f5c6cb);
border-radius: var(--radius-sm, 3px);
padding: var(--space-2, 8px);
margin-top: var(--space-3, 10px);
}
.status-info-notice {
background: var(--alert-info-bg, #d1ecf1);
border: 1px solid var(--alert-info-border, #bee5eb);
border-radius: var(--radius-sm, 3px);
padding: var(--space-2, 8px);
margin-top: var(--space-3, 10px);
}
.crypto-help-section {
margin-top: 30px;
padding: 15px;
background: var(--surface-container-high, #e9ecef);
border-radius: var(--radius-sm, 4px);
}
.crypto-empty-state {
text-align: center;
padding: var(--space-10, 40px);
color: var(--text-secondary, #6c757d);
}
/* Invoice layout classes */
.invoice-right-section {
text-align: right;
margin: 15px 0;
}
.invoice-total-section {
text-align: right;
margin: 20px 0;
font-size: 1.2em;
}
.invoice-payment-box {
background-color: var(--alert-info-bg, #f0f8ff);
padding: 15px;
border: 1px solid var(--color-navy, #4169e1);
border-radius: var(--radius-sm, 5px);
margin: 15px 0;
}
.invoice-margin-section {
margin-top: 15px;
}
.invoice-margin-small {
margin: 5px 0;
}
/* Status color classes */
.status-success {
color: var(--color-check, #28a745);
}
.status-warning {
color: var(--color-gold, #ffc107);
}
.status-info {
color: var(--text-secondary, #6c757d);
}
.status-error {
color: var(--color-danger, #dc3545);
}
.code-monospace {
font-size: 0.9em;
font-family: var(--font-mono, monospace);
}
/* Apply theme variables to existing elements (tokens defined in tokens.css) */
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
section.content {
background-color: var(--bg-primary);
color: var(--text-primary);
}
section.nav {
background-color: var(--bg-secondary);
color: var(--nav-text);
}
a {
color: var(--link-color);
}
input[type="text"],
input[type="tel"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="date"],
textarea {
background-color: var(--input-bg);
border-color: var(--input-border);
color: var(--input-text);
}
.well, .well2 {
background-color: var(--well-bg);
color: var(--text-primary);
}
[data-theme="dark"] .well,
[data-theme="dark"] .well2 {
background-color: var(--dark-button-bg, #2d3748);
background-image: url("/static/img/trans-blue.png");
border: 2px solid #7ab9ff;
box-shadow: 0 0 10px rgba(122, 185, 255, 0.3);
color: var(--text-primary);
}
/* Dark mode specific overrides for existing classes */
[data-theme="dark"] table tr:nth-child(even) {
background-color: #2d2d2d;
}
[data-theme="dark"] table tr:nth-child(odd) {
background-color: #333333;
}
[data-theme="dark"] .crypto-payment-card {
background: var(--card-bg);
border-color: var(--border-color);
color: var(--text-primary);
}
[data-theme="dark"] .status-warning-notice {
background: var(--notice-warning-bg);
border-color: var(--notice-warning-border);
color: var(--text-primary);
}
[data-theme="dark"] .status-error-notice {
background: var(--notice-error-bg);
border-color: var(--notice-error-border);
color: var(--text-primary);
}
[data-theme="dark"] .status-info-notice {
background: var(--notice-info-bg);
border-color: var(--notice-info-border);
color: var(--text-primary);
}
[data-theme="dark"] .crypto-help-section {
background: var(--bg-tertiary);
color: var(--text-primary);
}
[data-theme="dark"] .invoice-payment-box {
background-color: #1a365d;
border-color: #2c5282;
color: var(--text-primary);
}
/* Crypto wallet success indicators */
.success-indicator {
color: var(--success-color);
font-weight: bold;
}
[data-theme="dark"] .success-indicator {
color: var(--green-color);
font-weight: bold;
}
/* Theme toggle button */
.theme-toggle {
background: none;
border: 1px solid var(--border-color);
color: var(--text-primary);
padding: var(--space-2, 8px) var(--space-3, 12px);
border-radius: var(--radius-sm, 4px);
cursor: pointer;
font-size: var(--text-sm, 14px);
transition: background-color var(--duration-normal, 0.2s) var(--ease-standard, ease);
}
.theme-toggle:hover {
background-color: var(--bg-secondary);
}
.theme-toggle-icon {
margin-right: 5px;
}
/* Watch mode: sticky video within tall left wrapper */
.watch-mode .product-images {
position: sticky;
z-index: 10;
background: var(--bg-primary, #ffffff);
overflow: hidden;
max-width: 100%;
}
/* Watch video container — grid stacks all children in same cell for crossfade */
.watch-video-container {
display: grid;
position: relative;
overflow: hidden;
max-width: 100%;
min-width: 0;
}
.watch-video-container > * {
grid-area: 1 / 1;
}
.watch-video-container > video {
max-width: 100%;
max-height: 42vh;
width: auto;
height: auto;
}
/* Container fullscreen — promoted from <video> for seamless crossfade */
.watch-video-container:fullscreen,
.watch-video-container:-webkit-full-screen {
background: black;
display: grid;
place-items: center;
}
.watch-video-container:fullscreen > video,
.watch-video-container:-webkit-full-screen > video {
max-height: 100vh;
max-width: 100vw;
}
/* Incoming video during DJ crossfade — z-index above active */
.crossfade-incoming {
z-index: 2;
}
/* Unmute overlay — shown by JS when autoplay-with-sound is blocked */
.unmute-overlay {
position: absolute;
top: 10px;
right: 10px;
z-index: 20;
background: rgba(0, 0, 0, 0.7);
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
display: none;
}
/* Related content sidebar — "Up Next" */
.related-content {
margin-top: 20px;
text-align: left;
}
.related-content-header {
display: grid;
gap: 6px;
margin-bottom: 12px;
}
.ring-header-info {
display: grid;
grid-template-columns: auto auto auto 1fr;
gap: 8px;
align-items: center;
}
.ring-header-info .ring-progress {
justify-self: end;
}
.ring-header-controls {
display: grid;
grid-template-columns: repeat(4, auto);
gap: 8px 16px;
justify-content: end;
align-items: center;
}
/* Karaoke button gets its own row, right-aligned. */
.ring-header-controls .ring-karaoke-btn {
grid-column: 1 / -1;
justify-self: end;
}
/* Nav row: 3 buttons across 4 cols — stretch Next to fill the last
two columns so there's no empty-column gap on the right edge. */
.ring-header-controls #skip-prev-btn { grid-column: 1 / 2; }
.ring-header-controls #skip-random-btn { grid-column: 2 / 3; }
.ring-header-controls #skip-next-btn { grid-column: 3 / -1; }
.skip-next-btn {
font-size: 1.1em;
padding: 12px 24px;
cursor: pointer;
font-weight: var(--weight-semibold, 600);
border-radius: var(--radius-md, 8px);
}
.related-content-header h3 {
margin: 0;
font-size: 0.85em;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted, #888);
}
/* Autoplay toggle — iOS-style slider */
.watch-autoplay-label {
display: grid;
grid-template-columns: auto auto;
gap: 8px;
align-items: center;
cursor: pointer;
user-select: none;
}
.autoplay-label-text {
font-size: 0.75em;
color: var(--text-muted, #888);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.autoplay-slider {
width: 36px;
height: 20px;
background: var(--bg-tertiary, #ccc);
border-radius: 10px;
position: relative;
transition: background 0.2s;
}
.autoplay-slider::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 16px;
height: 16px;
background: white;
border-radius: 50%;
transition: transform 0.2s;
}
.watch-autoplay-label input {
display: none;
}
.watch-autoplay-label input:checked + .autoplay-slider {
background: var(--blue-color, #98b6fa);
}
.watch-autoplay-label input:checked + .autoplay-slider::after {
transform: translateX(16px);
}
.related-content-row {
display: grid;
grid-template-columns: 20px 1fr 28px;
gap: 0;
align-items: center;
margin-bottom: 2px;
border-radius: 6px;
transition: background 0.15s;
}
.related-content-row:hover {
background: var(--bg-secondary, rgba(0, 0, 0, 0.04));
}
.related-content-row-watched {
opacity: 0.45;
}
.related-content.fresh-mode .related-content-row-watched {
display: none;
}
/* Media type filter — hide rows by data-media-type */
.related-content.hide-video .related-content-row[data-media-type="video"] { display: none; }
.related-content.hide-audio .related-content-row[data-media-type="audio"] { display: none; }
.related-content.hide-image .related-content-row[data-media-type="image"] { display: none; }
.related-content.hide-document .related-content-row[data-media-type="document"] { display: none; }
.related-content.hide-other .related-content-row[data-media-type="other"] { display: none; }
.watch-fresh-label {
display: grid;
grid-template-columns: auto auto;
gap: 6px;
align-items: center;
font-size: 0.85em;
cursor: pointer;
}
.watch-fresh-label input {
display: none;
}
.watch-fresh-label input:checked + .autoplay-slider {
background: var(--blue-color, #98b6fa);
}
.watch-fresh-label input:checked + .autoplay-slider::after {
transform: translateX(16px);
}
.fresh-label-text {
font-size: 0.85em;
color: var(--text-muted, #999);
}
.watch-cinema-label {
display: grid;
grid-template-columns: auto auto;
gap: 6px;
align-items: center;
font-size: 0.85em;
cursor: pointer;
}
.watch-cinema-label input {
display: none;
}
.watch-cinema-label input:checked + .autoplay-slider {
background: var(--blue-color, #98b6fa);
}
.watch-cinema-label input:checked + .autoplay-slider::after {
transform: translateX(16px);
}
.cinema-label-text {
font-size: 0.85em;
color: var(--text-muted, #999);
}
/* Media type filter bar */
.ring-filter-controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, auto));
grid-auto-flow: column;
gap: 6px;
justify-content: end;
align-items: center;
}
.ring-filter-btn {
font-size: 0.7em;
padding: 2px 8px;
border: 1px solid var(--border-color, #ccc);
border-radius: 12px;
background: transparent;
color: var(--text-muted, #999);
cursor: pointer;
white-space: nowrap;
}
.ring-filter-btn.active {
background: var(--blue-color, #5871ad);
color: white;
border-color: var(--blue-color, #5871ad);
}
.ring-karaoke-btn {
font-size: 0.75em;
padding: 2px 10px;
border: 1px solid var(--border-color, #ccc);
border-radius: 12px;
background: transparent;
color: var(--text-muted, #999);
cursor: pointer;
white-space: nowrap;
}
.ring-karaoke-btn.active {
background: var(--blue-color, #5871ad);
color: white;
border-color: var(--blue-color, #5871ad);
}
.ring-karaoke-btn:disabled {
cursor: wait;
opacity: 0.6;
}
.related-content-row-current {
background-color: var(--blue-color, #5871ad);
color: white;
border-radius: 4px;
padding: 4px 0;
}
.related-content-row-current .related-content-index {
color: white;
}
.related-content-row-current .queue-add-btn {
color: white;
}
.related-content-now-playing {
font-weight: bold;
}
.related-content-now-playing .related-content-title {
-webkit-line-clamp: unset;
overflow: visible;
}
.related-content-row-prev {
opacity: 0.55;
}
.related-content-comments-link,
.product-comments-link {
display: none;
}
.ring-progress {
font-size: 0.8em;
color: var(--text-muted, #999);
font-variant-numeric: tabular-nums;
}
.ring-loops-badge {
font-size: 0.75em;
font-weight: bold;
padding: 1px 6px;
border-radius: 10px;
background-color: var(--blue-color, #5871ad);
color: white;
}
.ring-mod-badge {
font-size: 0.65em;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 1px 5px;
border-radius: 10px;
background-color: #48bb78;
color: white;
}
.watch-direction-label {
display: grid;
grid-template-columns: auto auto;
gap: 6px;
align-items: center;
font-size: 0.85em;
cursor: pointer;
}
.watch-direction-label input {
display: none;
}
.watch-direction-label input:checked + .autoplay-slider {
background: var(--blue-color, #98b6fa);
}
.watch-direction-label input:checked + .autoplay-slider::after {
transform: translateX(16px);
}
.direction-label-text {
font-size: 0.85em;
color: var(--text-muted, #999);
}
.related-content-index {
font-size: 0.75em;
color: var(--text-muted, #999);
text-align: center;
font-variant-numeric: tabular-nums;
}
.related-content-item {
display: grid;
grid-template-columns: 58px 1fr;
gap: 10px;
padding: 6px 4px;
text-decoration: none;
color: inherit;
border-radius: 4px;
align-items: center;
min-width: 0;
}
.related-content-item img {
max-width: 58px;
max-height: 58px;
width: auto;
height: auto;
border-radius: 4px;
}
.related-content-no-thumb {
display: block;
width: 58px;
height: 58px;
border-radius: 4px;
background: var(--bg-secondary, #e8e8e8);
}
.related-content-title {
font-size: 0.82em;
line-height: 1.3;
text-align: left;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Watch mode: audio container with album art */
.watch-audio-container {
position: relative;
text-align: center;
}
.watch-audio-container .audio-cover {
max-height: 42vh;
width: auto;
max-width: 100%;
display: block;
}
.watch-audio-container audio {
width: 100%;
margin-top: 8px;
}
/* Watch countdown overlay — compact bottom bar with frosted glass */
.watch-countdown {
position: relative;
display: grid;
grid-template-columns: 60px 1fr auto auto;
gap: 10px;
padding: 10px 14px;
align-items: center;
text-align: left;
background: var(--surface-secondary, #f6f8fa);
border: 1px solid var(--border-color, #dee2e6);
border-radius: var(--radius-md, 8px);
margin-top: 8px;
}
[data-theme="dark"] .watch-countdown {
background: var(--surface-secondary, #161b22);
border-color: var(--border-color, #7ab9ff);
}
.countdown-thumb {
grid-column: 1;
width: 60px;
height: auto;
border-radius: 4px;
}
.countdown-text {
grid-column: 2;
color: var(--text-primary, #333);
display: grid;
gap: 2px;
}
#countdown-title {
font-size: 0.85rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#countdown-number {
font-size: 1.5rem;
font-weight: bold;
color: var(--blue-color, #98b6fa);
}
.watch-countdown .mps-button {
padding: 6px 14px;
font-size: 0.85rem;
}
#countdown-play-now {
grid-column: 3;
}
#countdown-cancel {
grid-column: 4;
}
/* Queue UI */
#watch-queue {
margin-bottom: 16px;
}
#watch-queue h4 {
margin-bottom: 8px;
}
.queue-item {
display: grid;
grid-template-columns: 1fr auto;
gap: 8px;
align-items: center;
padding: 6px 0;
border-bottom: 1px solid var(--border-color, #ddd);
}
.queue-item-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.queue-remove-btn {
background: none;
border: none;
color: var(--text-secondary, #666);
cursor: pointer;
font-size: 1.2rem;
padding: 0 4px;
}
.queue-remove-btn:hover {
color: var(--text-primary, #333);
}
/* Queue add button inside related content row */
.queue-add-btn {
background: none;
border: none;
cursor: pointer;
font-size: 1.1rem;
padding: 4px;
color: var(--text-primary, #333);
border-radius: 50%;
width: 28px;
height: 28px;
display: grid;
place-items: center;
transition: background 0.15s, color 0.15s;
}
.queue-add-btn:hover {
background: var(--bg-secondary, rgba(0, 0, 0, 0.08));
color: var(--text-primary, #333);
}
@keyframes queue-row-flash {
0% { background: var(--green-color, #a3c765); box-shadow: 0 0 14px 4px #b388ff; color: #fff; }
100% { background: transparent; box-shadow: none; color: inherit; }
}
.related-content-row.queue-row-added {
animation: queue-row-flash 5s ease-out;
}
.related-content-row.queue-row-added a,
.related-content-row.queue-row-added .related-content-index,
.related-content-row.queue-row-added .queue-add-btn {
color: inherit;
}
/* Footer */
.mps-footer {
background-color: var(--bg-secondary, #f8f9fa);
border-top: 2px solid var(--border-color, #dee2e6);
margin-top: 40px;
padding: 40px 40px 24px;
}
.mps-footer-grid {
max-width: 100%;
margin: 0 auto 32px;
display: grid;
grid-template-columns: 1fr;
gap: 28px;
}
.mps-footer-brand {
display: grid;
gap: 8px;
}
.mps-footer-logo {
font-size: 1.4em;
font-weight: 550;
color: var(--text-primary, #333);
text-decoration: none;
}
.mps-footer-logo:hover {
color: var(--blue-color, #5871ad);
}
.mps-footer-tagline {
color: var(--text-muted, #777);
font-size: 14px;
max-width: 320px;
line-height: 1.5;
}
.mps-footer-group {
display: grid;
gap: 10px;
}
.mps-footer-group-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary, #333);
text-transform: uppercase;
letter-spacing: 0.05em;
white-space: nowrap;
}
.mps-footer-links {
display: grid;
gap: 8px;
}
.mps-footer-links a {
color: var(--text-muted, #777);
font-size: 14px;
font-weight: 400;
text-decoration: none;
white-space: nowrap;
}
.mps-footer-links a:hover {
color: var(--green-color, #a3c765);
}
.mps-footer-ctas {
max-width: 100%;
margin: 0 auto 24px;
display: grid;
grid-template-columns: auto auto;
justify-content: start;
gap: 12px;
padding: 20px 0;
border-top: 1px solid var(--border-color, #dee2e6);
border-bottom: 1px solid var(--border-color, #dee2e6);
}
.mps-footer-ctas a.mps-button {
min-width: 160px;
font-size: 14px;
padding-top: 10px;
padding-bottom: 10px;
}
.mps-footer-bottom {
text-align: center;
color: var(--text-muted, #999);
font-size: 12px;
max-width: 100%;
margin: 0 auto;
}
.mps-footer-bottom a {
color: var(--text-muted, #999);
text-decoration: underline;
font-weight: 400;
}
.mps-footer-bottom a:hover {
color: var(--green-color, #a3c765);
}
@media (min-width: 800px) {
.mps-footer-grid {
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: 32px;
}
}
/* Analytics Dashboard */
.analytics-page {
max-width: 1000px;
margin-left: auto;
margin-right: auto;
padding: 0 10px;
}
.analytics-header {
display: grid;
grid-template-columns: 1fr auto;
gap: var(--space-3, 12px);
align-items: center;
margin-bottom: var(--space-3, 12px);
}
.analytics-header h3 {
margin: 0;
}
.analytics-range-form {
display: grid;
grid-template-columns: auto auto auto;
gap: var(--space-2, 8px);
align-items: center;
margin: 0;
}
.analytics-range-form label {
font-size: var(--font-size-sm, 0.875rem);
color: var(--text-muted, #666);
}
.analytics-range-form select {
padding: var(--space-1, 4px) var(--space-2, 8px);
border-radius: var(--radius-sm, 4px);
border: 1px solid var(--border-color, #dee2e6);
background: var(--surface-color, #fff);
color: var(--text-color, #222);
font-size: var(--font-size-sm, 0.875rem);
}
.analytics-overview {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-bottom: 30px;
}
.analytics-overview-item {
display: grid;
gap: 2px;
text-align: center;
padding: 10px;
}
.analytics-overview-value {
font-size: 1.4em;
font-weight: bold;
color: var(--text-primary);
}
.analytics-overview-label {
font-size: 0.8em;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.analytics-table-wrap {
overflow-x: auto;
margin-bottom: 30px;
}
.analytics-table {
width: 100%;
border-collapse: collapse;
}
.analytics-table th {
font-size: 0.8em;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
border-bottom: 2px solid var(--border-color, #dee2e6);
padding: 6px 8px;
}
.analytics-table td {
padding: 6px 8px;
border-bottom: 1px solid var(--border-light, #e9ecef);
}
.analytics-table tbody tr:last-child td {
border-bottom: none;
}
.analytics-num {
text-align: right;
font-variant-numeric: tabular-nums;
}
.analytics-trend-up {
color: var(--green-color, #a3c765);
}
.analytics-trend-down {
color: var(--text-muted, #999);
}
.analytics-hint {
font-size: 0.85em;
color: var(--text-muted);
margin-top: 0;
margin-bottom: 10px;
}
.analytics-pair {
display: grid;
grid-template-columns: 1fr;
gap: 30px;
margin-bottom: 30px;
}
.analytics-privacy {
font-size: 0.8em;
color: var(--text-muted);
margin-top: 40px;
padding-top: 20px;
border-top: 1px solid var(--border-light, #e9ecef);
}
/* Override default table zebra striping inside analytics tables */
.analytics-table tr:nth-child(even),
.analytics-table tr:nth-child(odd) {
background-color: transparent;
}
/* --- Analytics Charts --- */
/* SVG daily views chart container */
.analytics-chart-svg {
width: 100%;
margin-bottom: 24px;
}
.analytics-chart-svg svg {
width: 100%;
height: auto;
display: block;
}
/* CSS horizontal bar rows for traffic/devices */
.analytics-bar-rows {
margin-bottom: 24px;
}
.analytics-bar-row {
display: table;
width: 100%;
table-layout: fixed;
margin-bottom: 6px;
font-size: 0.9em;
}
.analytics-bar-label {
display: table-cell;
width: 80px;
vertical-align: middle;
padding-right: 8px;
color: var(--text-primary);
}
.analytics-bar-track {
display: table-cell;
vertical-align: middle;
padding: 0 8px;
}
.analytics-bar-fill {
display: block;
height: 16px;
background: var(--green-color, #a3c765);
border-radius: 2px;
min-width: 2px;
}
.analytics-bar-value {
display: table-cell;
width: 100px;
vertical-align: middle;
text-align: right;
font-variant-numeric: tabular-nums;
color: var(--text-muted);
font-size: 0.85em;
}
/* Inline mini bar for table cells (top products 7d column) */
.analytics-inline-bar {
display: inline-block;
vertical-align: middle;
width: 50px;
height: 10px;
background: var(--bg-tertiary, #e9ecef);
border-radius: 2px;
margin-left: 6px;
}
.analytics-inline-bar-fill {
display: block;
height: 100%;
background: var(--green-color, #a3c765);
border-radius: 2px;
}
@media (min-width: 960px) {
.analytics-overview {
grid-template-columns: repeat(3, 1fr);
}
.analytics-pair {
grid-template-columns: 1fr 1fr;
}
.analytics-bar-label {
width: 100px;
}
.analytics-bar-value {
width: 120px;
}
}
.analytics-bar-row--wide .analytics-bar-label {
width: 140px;
}
@media (min-width: 960px) {
.analytics-bar-row--wide .analytics-bar-label {
width: 180px;
}
}
.price-history-current td {
font-weight: bold;
}
/* Color filter modes — pure CSS filter chains, no SVG needed */
html[data-color-filter="1"] {
filter: grayscale(100%);
}
html[data-color-filter="2"] {
/* Red monochrome */
filter: grayscale(100%) sepia(100%) hue-rotate(-30deg) saturate(300%);
}
html[data-color-filter="3"] {
/* Green monochrome */
filter: grayscale(100%) sepia(100%) hue-rotate(85deg) saturate(300%);
}
html[data-color-filter="4"] {
/* Blue monochrome */
filter: grayscale(100%) sepia(100%) hue-rotate(200deg) saturate(300%);
}
html[data-color-filter="5"] {
/* Yellow (red+green) monochrome */
filter: grayscale(100%) sepia(100%) hue-rotate(25deg) saturate(300%);
}
html[data-color-filter="6"] {
/* Magenta (red+blue) monochrome */
filter: grayscale(100%) sepia(100%) hue-rotate(265deg) saturate(300%);
}
html[data-color-filter="7"] {
/* Cyan (green+blue) monochrome */
filter: grayscale(100%) sepia(100%) hue-rotate(145deg) saturate(300%);
}
/* ---- Sandbox mode toolbar ---- */
.sandbox-toolbar {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
}
.sandbox-toggle-btn {
padding: 10px 16px;
border: none;
border-radius: 8px;
background: var(--pico-primary);
color: var(--pico-primary-inverse);
cursor: pointer;
font-size: 14px;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.sandbox-toggle-btn:hover {
opacity: 0.9;
}
.sandbox-panel {
position: fixed;
bottom: 70px;
right: 20px;
width: 340px;
max-height: 70vh;
overflow-y: auto;
background: var(--pico-background-color);
border: 1px solid var(--pico-muted-border-color);
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
z-index: 9999;
padding: 12px;
}
.sandbox-panel-header {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
padding-bottom: 8px;
border-bottom: 1px solid var(--pico-muted-border-color);
margin-bottom: 8px;
font-weight: bold;
font-size: 14px;
}
.sandbox-close-btn {
background: none;
border: none;
font-size: 20px;
cursor: pointer;
color: var(--pico-color);
padding: 0 4px;
}
.sandbox-presets {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
margin-bottom: 12px;
}
.sandbox-preset-btn {
padding: 6px 4px;
border: 1px solid var(--pico-muted-border-color);
border-radius: 6px;
background: var(--pico-background-color);
color: var(--pico-color);
cursor: pointer;
font-size: 11px;
text-align: center;
transition: border-color 0.15s;
}
.sandbox-preset-btn.active {
border-color: var(--pico-primary);
background: var(--pico-primary);
color: var(--pico-primary-inverse);
}
.sandbox-preset-category {
grid-column: 1 / -1;
font-size: 11px;
font-weight: bold;
color: var(--pico-muted-color);
margin-top: 6px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.sandbox-sliders {
margin-bottom: 12px;
}
.sandbox-slider-row {
display: grid;
grid-template-columns: 80px 1fr 36px;
align-items: center;
gap: 8px;
margin-bottom: 4px;
font-size: 12px;
}
.sandbox-slider-row input[type="range"] {
width: 100%;
margin: 0;
padding: 0;
height: 20px;
}
.sandbox-slider-value {
text-align: right;
font-variant-numeric: tabular-nums;
color: var(--pico-muted-color);
font-size: 11px;
}
.sandbox-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid var(--pico-muted-border-color);
}
.sandbox-action-btn {
padding: 8px;
border: 1px solid var(--pico-muted-border-color);
border-radius: 6px;
background: var(--pico-background-color);
color: var(--pico-color);
cursor: pointer;
font-size: 12px;
text-align: center;
transition: border-color 0.15s;
}
.sandbox-action-btn:hover {
border-color: var(--pico-primary);
}
.sandbox-action-btn.sandbox-export-btn {
grid-column: 1 / -1;
}
.sandbox-face-section {
margin-top: 12px;
padding-top: 8px;
border-top: 1px solid var(--pico-muted-border-color);
}
.sandbox-face-controls {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 6px;
margin-top: 8px;
}
.sandbox-color-row {
display: grid;
grid-template-columns: 80px 1fr;
align-items: center;
gap: 8px;
margin-top: 8px;
font-size: 12px;
}
.sandbox-color-row input[type="color"] {
width: 100%;
height: 28px;
border: 1px solid var(--pico-muted-border-color);
border-radius: 4px;
padding: 2px;
cursor: pointer;
}
.sandbox-status {
font-size: 11px;
color: var(--pico-muted-color);
text-align: center;
padding: 4px 0;
}
/* Sandbox canvas overlay for face effects */
.sandbox-canvas-overlay {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
z-index: 5;
}
/* Mobile: full-width panel */
@media (max-width: 800px) {
.sandbox-toolbar {
bottom: 10px;
right: 10px;
}
.sandbox-panel {
bottom: 60px;
right: 10px;
left: 10px;
width: auto;
max-height: 50vh;
}
.sandbox-presets {
grid-template-columns: repeat(3, 1fr);
}
}
/* Edit page media previews */
.edit-media-preview {
width: auto;
max-width: 100%;
max-height: 33vh;
border-radius: 4px;
}
.edit-pdf-preview {
width: 100%;
height: 50vh;
border: 1px solid #ccc;
border-radius: 4px;
}
/* Gift Card */
.gift-card-form {
display: grid;
gap: var(--space-4, 16px);
}
.gift-card-slider-group {
display: grid;
grid-template-columns: 1fr auto;
gap: var(--space-4, 16px);
align-items: center;
}
.gift-card-slider {
width: 100%;
}
.gift-card-amount-input-group {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-1, 4px);
}
.gift-card-currency {
font-size: var(--text-lg, 1.25rem);
font-weight: bold;
}
.gift-card-amount-input {
width: 100px;
font-size: var(--text-lg, 1.25rem);
padding: var(--space-2, 8px);
border: 1px solid var(--border-default, #ccc);
border-radius: var(--radius-sm, 4px);
background: var(--surface-default, #fff);
color: var(--text-primary, #333);
}
.gift-card-balance-form {
display: grid;
grid-template-columns: 1fr auto;
gap: var(--space-3, 12px);
align-items: center;
}
.cart-gift-card-apply {
margin-top: var(--space-3, 12px);
}
.cart-gift-card-apply form {
display: grid;
grid-template-columns: 1fr auto;
gap: var(--space-3, 12px);
align-items: center;
}
.badge-success {
color: var(--success, #28a745);
font-weight: bold;
}
.badge-error {
color: var(--error, #dc3545);
font-weight: bold;
}
.badge-info {
color: var(--info, #17a2b8);
font-weight: bold;
}
/* MPS-20 + MPS-21: auction & offer components */
.auction-page,
.offer-page {
padding: var(--space-3);
}
.auction-stats {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: var(--space-3);
}
.auction-stat {
display: grid;
gap: var(--space-1);
}
.auction-stat-label {
color: var(--color-text-muted, #888);
font-size: 0.85em;
}
.auction-stat-value {
font-size: 1.5em;
font-weight: bold;
}
.auction-bid-form {
display: grid;
gap: var(--space-2);
}
.auction-state-badge,
.offer-state-badge {
display: inline-block;
padding: var(--space-1) var(--space-3);
border-radius: var(--radius-md, 4px);
font-size: 0.85em;
font-weight: bold;
text-align: center;
color: #fff;
background: var(--color-text-muted, #888);
}
.auction-state-0 { background: var(--color-text-muted, #888); } /* Draft */
.auction-state-1 { background: var(--color-info, #17a2b8); } /* Scheduled */
.auction-state-2 { background: var(--color-success, #28a745); } /* Active */
.auction-state-3 { background: var(--color-warning, #ffc107); color: #333; } /* Ended */
.auction-state-4 { background: var(--color-primary, #5871ad); } /* Settled */
.auction-state-5 { background: var(--color-error, #dc3545); } /* Cancelled */
.offer-state-0 { background: var(--color-info, #17a2b8); } /* Pending */
.offer-state-1 { background: var(--color-success, #28a745); } /* Accepted */
.offer-state-2 { background: var(--color-primary, #5871ad); } /* Countered */
.offer-state-3 { background: var(--color-error, #dc3545); } /* Declined */
.offer-state-4 { background: var(--color-text-muted, #888); } /* Expired */
.offer-state-5 { background: var(--color-text-muted, #888); } /* Withdrawn */
.offer-state-6 { background: var(--color-success, #28a745); } /* Paid */
.auction-flash {
margin-top: var(--space-3);
padding: var(--space-2) var(--space-3);
border-radius: var(--radius-md, 4px);
}
.auction-flash:empty {
display: none;
}
.auction-flash-success {
background: var(--color-success-subtle, #d4edda);
color: var(--color-success-strong, #155724);
}
.auction-flash-error {
background: var(--color-error-subtle, #f8d7da);
color: var(--color-error-strong, #721c24);
}
.offer-events {
list-style: none;
padding: 0;
}
.offer-event {
padding: var(--space-2) 0;
border-bottom: 1px solid var(--color-border, #eee);
}
.offer-event:last-child {
border-bottom: 0;
}