← back to Dw Theme Compact Toolbar
assets/recently-viewed.css
498 lines
/* ==========================================================================
recently-viewed.css
Designer Wallcoverings — Recently Viewed Carousel + Quick-Add Modal
BEM naming (.rv-*), --rv-* custom properties, no external font imports.
========================================================================== */
/* --------------------------------------------------------------------------
Design tokens
-------------------------------------------------------------------------- */
:root {
--rv-bg: #fafaf8;
--rv-surface: #ffffff;
--rv-text-primary: #1a1a1a;
--rv-text-secondary: #6b6b6b;
--rv-text-muted: #9a9a9a;
--rv-accent: #c8b89a;
--rv-border: rgba(0, 0, 0, 0.07);
--rv-shadow: 0 2px 12px rgba(0, 0, 0, 0.07);
--rv-shadow-hover: 0 8px 28px rgba(0, 0, 0, 0.13);
--rv-overlay: rgba(20, 18, 16, 0.55);
--rv-radius: 4px;
--rv-font: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
sans-serif;
--rv-transition: 0.22s ease;
--rv-img-placeholder: #ece9e4;
--rv-section-px: clamp(20px, 5vw, 80px);
--rv-gap: clamp(14px, 1.5vw, 24px);
--rv-card-width: clamp(145px, 19vw, 212px);
/* Button states */
--rv-btn-loading-bg: #555;
--rv-btn-success-bg: #4a7c59;
--rv-btn-error-bg: #b94040;
}
@media (max-width: 480px) {
:root {
--rv-section-px: 20px;
--rv-gap: 14px;
--rv-card-width: 145px;
}
}
@media (min-width: 481px) and (max-width: 900px) {
:root {
--rv-section-px: 36px;
--rv-gap: 18px;
--rv-card-width: 158px;
}
}
@media (min-width: 901px) {
:root {
--rv-section-px: 56px;
--rv-gap: 22px;
--rv-card-width: clamp(188px, 14.5vw, 212px);
}
}
/* --------------------------------------------------------------------------
Section wrapper
-------------------------------------------------------------------------- */
.rv-section {
background: var(--rv-bg);
padding: 56px 0 60px;
font-family: var(--rv-font);
-webkit-font-smoothing: antialiased;
}
/* --------------------------------------------------------------------------
Section header — heading + arrows row
-------------------------------------------------------------------------- */
.rv-section__header {
display: flex;
align-items: center;
justify-content: space-between;
padding-inline: var(--rv-section-px);
margin-bottom: 28px;
}
.rv-section__heading {
font-size: clamp(17px, 2vw, 22px);
font-weight: 400;
letter-spacing: -0.02em;
color: var(--rv-text-primary);
margin: 0;
text-transform: none !important;
}
/* --------------------------------------------------------------------------
Arrow navigation
-------------------------------------------------------------------------- */
.rv-arrows {
display: flex;
gap: 8px;
align-items: center;
}
.rv-arrow {
width: 40px;
height: 40px;
border-radius: 50%;
border: 1.5px solid var(--rv-border);
background: var(--rv-surface);
color: var(--rv-text-primary);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition:
border-color var(--rv-transition),
background var(--rv-transition),
color var(--rv-transition),
opacity var(--rv-transition);
box-shadow: var(--rv-shadow);
flex-shrink: 0;
padding: 0;
}
.rv-arrow:hover {
border-color: var(--rv-accent);
background: var(--rv-accent);
color: #fff;
}
.rv-arrow:focus-visible {
outline: 2px solid var(--rv-accent);
outline-offset: 2px;
}
.rv-arrow--hidden {
opacity: 0;
pointer-events: none;
}
/* --------------------------------------------------------------------------
Scroll track
-------------------------------------------------------------------------- */
.rv-track {
display: flex;
gap: var(--rv-gap);
overflow-x: auto;
scroll-snap-type: x mandatory;
padding-inline: var(--rv-section-px);
scrollbar-width: none;
-ms-overflow-style: none;
}
.rv-track::-webkit-scrollbar {
display: none;
}
/* --------------------------------------------------------------------------
Track item (scroll snap target + role=listitem container)
-------------------------------------------------------------------------- */
.rv-track__item {
scroll-snap-align: start;
flex-shrink: 0;
}
/* --------------------------------------------------------------------------
Product card
-------------------------------------------------------------------------- */
.rv-card {
width: var(--rv-card-width);
background: var(--rv-surface);
border-radius: 6px;
overflow: hidden;
cursor: pointer;
border: none;
padding: 0;
text-align: left;
display: block;
box-shadow: var(--rv-shadow);
transform: scale(1);
transition:
transform var(--rv-transition),
box-shadow var(--rv-transition);
font-family: var(--rv-font);
}
.rv-card:hover {
transform: scale(1.03);
box-shadow: var(--rv-shadow-hover);
}
.rv-card:focus-visible {
outline: 2px solid var(--rv-accent);
outline-offset: 2px;
}
/* Card — image wrapper */
.rv-card__img-wrap {
width: 100%;
aspect-ratio: 1 / 1;
overflow: hidden;
background: var(--rv-img-placeholder);
}
.rv-card__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform 0.38s ease;
}
.rv-card:hover .rv-card__img {
transform: scale(1.06);
}
/* Card — text body */
.rv-card__body {
padding: 14px 16px 18px;
}
.rv-card__vendor {
font-size: 10px;
font-weight: 500;
letter-spacing: 0.09em;
text-transform: uppercase;
color: var(--rv-text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 4px;
}
.rv-card__title {
font-size: 13px;
font-weight: 450;
line-height: 1.45;
color: var(--rv-text-primary);
letter-spacing: -0.005em;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 8px;
min-height: 37px;
}
.rv-card__price {
font-size: 13px;
font-weight: 400;
color: var(--rv-text-secondary);
}
/* --------------------------------------------------------------------------
Modal overlay
-------------------------------------------------------------------------- */
.rv-overlay {
position: fixed;
inset: 0;
z-index: 9000;
background: var(--rv-overlay);
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
opacity: 0;
animation: rv-fade-in 0.18s ease forwards;
}
.rv-overlay[hidden] {
display: none !important;
}
/* --------------------------------------------------------------------------
Modal panel
-------------------------------------------------------------------------- */
.rv-modal {
position: relative;
background: var(--rv-surface);
border-radius: 8px;
width: 100%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.18);
opacity: 0;
transform: translateY(16px);
animation: rv-slide-up 0.22s ease 0.04s forwards;
scrollbar-width: thin;
scrollbar-color: var(--rv-border) transparent;
}
.rv-modal::-webkit-scrollbar { width: 4px; }
.rv-modal::-webkit-scrollbar-track { background: transparent; }
.rv-modal::-webkit-scrollbar-thumb {
background: var(--rv-border);
border-radius: 2px;
}
/* --------------------------------------------------------------------------
Modal — close button
-------------------------------------------------------------------------- */
.rv-modal__close {
position: absolute;
top: 14px;
right: 14px;
z-index: 1;
width: 34px;
height: 34px;
border-radius: 50%;
border: none;
background: transparent;
color: var(--rv-text-secondary);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition:
color var(--rv-transition),
background var(--rv-transition);
padding: 0;
}
.rv-modal__close:hover {
color: var(--rv-text-primary);
background: rgba(0, 0, 0, 0.06);
}
.rv-modal__close:focus-visible {
outline: 2px solid var(--rv-accent);
outline-offset: 2px;
}
/* --------------------------------------------------------------------------
Modal — image
-------------------------------------------------------------------------- */
.rv-modal__img-wrap {
width: 100%;
aspect-ratio: 1 / 1;
overflow: hidden;
background: var(--rv-img-placeholder);
border-radius: 8px 8px 0 0;
}
.rv-modal__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* --------------------------------------------------------------------------
Modal — body copy
-------------------------------------------------------------------------- */
.rv-modal__body {
padding: 28px 32px 32px;
}
.rv-modal__vendor {
font-size: 11px;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--rv-text-muted);
margin-bottom: 6px;
}
.rv-modal__title {
font-size: 20px;
font-weight: 500;
line-height: 1.3;
color: var(--rv-text-primary);
letter-spacing: -0.01em;
margin-bottom: 10px;
}
.rv-modal__price {
font-size: 16px;
font-weight: 400;
color: var(--rv-text-secondary);
margin-bottom: 28px;
}
/* --------------------------------------------------------------------------
Modal — Add Sample button (primary CTA)
-------------------------------------------------------------------------- */
.rv-modal__btn {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
padding: 15px 24px;
background: var(--rv-text-primary);
color: #fff;
border: none;
border-radius: var(--rv-radius);
font-family: var(--rv-font);
font-size: 13px;
font-weight: 500;
letter-spacing: 0.04em;
cursor: pointer;
transition: background var(--rv-transition);
margin-bottom: 16px;
}
.rv-modal__btn:hover:not(:disabled) {
background: #2e2e2e;
}
.rv-modal__btn:focus-visible {
outline: 2px solid var(--rv-accent);
outline-offset: 2px;
}
.rv-modal__btn:disabled {
cursor: not-allowed;
}
/* Loading state — spinner replaces label */
.rv-modal__btn--loading {
background: var(--rv-btn-loading-bg);
pointer-events: none;
}
.rv-modal__btn--loading .rv-modal__btn-label {
visibility: hidden;
width: 0;
overflow: hidden;
}
.rv-modal__btn--loading::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.35);
border-top-color: #fff;
border-radius: 50%;
animation: rv-spin 0.65s linear infinite;
flex-shrink: 0;
}
/* Success state */
.rv-modal__btn--success {
background: var(--rv-btn-success-bg);
pointer-events: none;
}
/* Error / unavailable state */
.rv-modal__btn--error {
background: var(--rv-btn-error-bg);
pointer-events: none;
}
/* --------------------------------------------------------------------------
Modal — "View full product" link
-------------------------------------------------------------------------- */
.rv-modal__link-wrap {
text-align: center;
}
.rv-modal__link {
font-size: 13px;
color: var(--rv-text-secondary);
text-decoration: none;
border-bottom: 1px solid var(--rv-border);
padding-bottom: 1px;
transition:
color var(--rv-transition),
border-color var(--rv-transition);
}
.rv-modal__link:hover {
color: var(--rv-text-primary);
border-color: var(--rv-text-primary);
}
.rv-modal__link:focus-visible {
outline: 2px solid var(--rv-accent);
outline-offset: 2px;
border-radius: 2px;
}
/* --------------------------------------------------------------------------
Keyframes
-------------------------------------------------------------------------- */
@keyframes rv-fade-in {
to { opacity: 1; }
}
@keyframes rv-slide-up {
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes rv-spin {
to { transform: rotate(360deg); }
}