Puts the monogram to the left of "Redefined Designs" in the site header. Inline SVG rather than an <img src="/favicon.svg"> for two reasons. The tile is drawn in currentColor so it follows the antd text token and inverts with the app's own theme switch — the favicon file inverts on prefers-color-scheme, which tracks the operating system and would disagree with the app whenever someone toggles the theme themselves. And the letters are knocked out with a mask rather than painted in the background colour, so the mark sits correctly on any surface instead of carrying a backdrop that only matches this header. The mask id is generated per instance, since two marks on one page would otherwise share an id and the second would reference the first. It is stripped to alphanumerics because React's generated ids contain colons. Marked aria-hidden: the wordmark beside it already says the name, so announcing it again would be noise. Verified by screenshotting the header in both themes rather than by reasoning about the colours.
171 lines
3.5 KiB
CSS
Executable File
171 lines
3.5 KiB
CSS
Executable File
body { margin: 0; }
|
|
|
|
.item-card .card-cover-img { width: 100%; height: 220px; object-fit: cover; display: block; }
|
|
.item-card .card-cover-placeholder { width: 100%; height: 220px; background: #eee; }
|
|
.price { font-weight: 600; margin: 8px 0; font-size: 16px; }
|
|
.paypal-slot { margin-top: 8px; }
|
|
|
|
.carousel-wrap { position: relative; }
|
|
.carousel-arrow {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
z-index: 2;
|
|
opacity: 0.85;
|
|
}
|
|
.carousel-arrow-left { left: 8px; }
|
|
.carousel-arrow-right { right: 8px; }
|
|
.carousel-count {
|
|
position: absolute;
|
|
bottom: 8px;
|
|
right: 8px;
|
|
background: rgba(0,0,0,0.6);
|
|
color: #fff;
|
|
font-size: 11px;
|
|
padding: 2px 8px;
|
|
border-radius: 10px;
|
|
z-index: 2;
|
|
}
|
|
|
|
.markdown-body { font-size: 14px; }
|
|
.markdown-body p { margin: 4px 0; }
|
|
.markdown-body ul, .markdown-body ol { margin: 4px 0; padding-left: 20px; }
|
|
.markdown-body h1, .markdown-body h2, .markdown-body h3 { font-size: 15px; margin: 8px 0 4px; }
|
|
|
|
/* Site header — wraps to two rows on narrow viewports instead of overflowing */
|
|
.site-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: 8px 16px;
|
|
height: auto;
|
|
min-height: 64px;
|
|
padding: 12px 24px;
|
|
line-height: normal;
|
|
}
|
|
|
|
.site-header-brand {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* The mark holds its size while the wordmark absorbs the squeeze. */
|
|
.site-header-brand svg {
|
|
flex: none;
|
|
}
|
|
|
|
.site-header-title {
|
|
margin: 0 !important;
|
|
font-size: clamp(16px, 5vw, 24px);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
}
|
|
|
|
.site-header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.site-header {
|
|
padding: 10px 12px;
|
|
}
|
|
.site-header-actions .ant-btn {
|
|
padding-left: 10px;
|
|
padding-right: 10px;
|
|
font-size: 13px;
|
|
}
|
|
}
|
|
/* Filter bar: the Filters button sits inline with the active-filter chips on
|
|
desktop; on a narrow screen the chips wrap onto their own line beneath it. */
|
|
.filter-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.active-filter-chips {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 4px;
|
|
}
|
|
|
|
.active-filter-chips .ant-tag {
|
|
margin-inline-end: 0;
|
|
}
|
|
|
|
.item-category {
|
|
display: block;
|
|
font-size: 12px;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.item-tags {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 4px 0;
|
|
margin: 8px 0 4px;
|
|
}
|
|
|
|
@media (max-width: 575px) {
|
|
.filter-bar {
|
|
align-items: flex-start;
|
|
}
|
|
.filter-bar > .ant-btn {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
/* Admin inventory filter row — always visible above the table, wrapping onto
|
|
further lines on narrow screens rather than scrolling horizontally. */
|
|
.inventory-filters {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
/* Admin category tree node: name, item count, then actions pushed to the
|
|
right. Without this the three run together as one unbroken string. */
|
|
.admin-category-node {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
width: 100%;
|
|
}
|
|
|
|
.admin-category-node > span:first-child {
|
|
font-weight: 500;
|
|
}
|
|
|
|
.admin-category-node .ant-space {
|
|
margin-left: auto;
|
|
}
|
|
|
|
/* Item card title row: name on the left, favorite toggle on the right. */
|
|
.item-card-title {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
}
|
|
|
|
.item-card-title .ant-typography {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|