The related content sidebar now shows all ring items from the current
position forward, matching content.py behavior. This means the sidebar
never "runs out" of items — Fresh mode hides watched items and reveals
the full remaining ring. Items beyond offset 7 still use the
related-content-overflow CSS class for mobile.
The ring was only populated from localStorage or during SPA navigation.
First visits (empty localStorage) or cross-shop visits (stale ring)
left ringProductIds empty, causing the related content sidebar to show
only the current product. Now:
- On page load, if localStorage ring is empty, fetch from watch JSON
- Invalidate stale rings when current product is not in the saved ring
- Skip discovery ring reforge for non-production shops (MPS-14)
- Block settings POST when trial expired, except environment and
bucket settings needed for onboarding (MPS-15)
- BYOB upload enforcement is a soft prompt (trial tip in settings)
rather than hard block — new users need to upload during trial
MPS-14: Add environment column (production/staging/development) to shops.
Non-production shops excluded from feeds, search, and discovery.
Environment banner in base template. Settings UI and creation selector.
MPS-15: Add 21-day free trial with trial_started_timestamp on shop
creation. Properties: is_trial_active, is_trial_expired, trial_days_remaining,
is_active. Grandfathered pre-trial shops (NULL timestamp = paid).
Trial banner in base template.
MPS-16: BYOB (Bring Your Own Bucket) - per-shop S3 storage with
primary_s3_* columns. Shop-aware request methods (shop_uploads_client,
shop_bucket_name, shop_cdn_endpoint) that fall back to MPS default.
All templates and views updated from global to shop-aware S3 references.
Bucket settings UI in shop settings.
Migration: 9884324a48e3 (idempotent, 11 new columns on mps_shop).
Tests: 14 unit tests + 8 functional tests (712 total, all pass).
Variable-amount gift cards purchasable with any payment method.
Code-based redemption at checkout (applied to cart like coupons).
Partial use across multiple purchases, never expire. Shop owners
control min/max amounts and can disable individual cards.
Models: GiftCard, GiftCardTransaction, CartGiftCard + migration.
Views: purchase page, cart apply/remove, shop admin manage/detail/toggle.
Templates: gift_card.j2, gift_card_manage.j2, gift_card_detail.j2.
Cart integration: gift cards deduct after coupons in all checkout paths.
Tests: 10 new unit tests covering model logic (677 total pass).
Adjust login card spacing for smaller screens and add overflow hidden to main content sections. Refine logo sizing across viewport sizes to prevent it from dominating on mobile devices.
- Add white-space: nowrap to section.log-in links, .user-display-name,
.cart-and-count, .mps-button, .mps-footer-links a, .mps-footer-group-title
- Prevents sloppy word breaks on "My Account", "Cart $0.00", etc.
- Remove .well from login-card to prevent padding/bg override
- Add border-radius and border directly to .login-card
- Bump specificity on .landing-feature-card.well and .landing-cta-card.well
- Constrain hero CTA button min-width to 180px
- Add display:block to .login-form-input for reliable full-width
Move :root and [data-theme="dark"] variable blocks from common.css into
tokens.css so the entire theme system lives in one file. Replace ~38
hardcoded #2d3748 dark button backgrounds with var(--dark-button-bg).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace ~150 hardcoded color, spacing, radius, font, and border values
with CSS custom property references from tokens.css. Every replacement
uses var() with the original value as fallback, ensuring zero visual
change while establishing the token-based foundation.
Categories migrated:
- Colors: button backgrounds, link color, status text, alert bg/text/border
- Surfaces: wells, content bg, table stripes, card bg, input bg
- Borders: input borders, thumbnails, comment replies, crypto cards
- Border radius: buttons, inputs, wells, serp items, alerts, cards
- Typography: font-family, font-size, font-weight on buttons/labels
- Spacing: padding, margins on buttons, inputs, coupons, notices
- Motion: theme toggle transition uses duration/easing tokens
Dark mode [data-theme="dark"] blocks left untouched — they override
via the existing variable system and will be consolidated in a future pass.