= h($product['name']) ?>
+= h($product['lead_time']) ?>
+= h($product['short_description']) ?>
+diff --git a/assets/css/custom.css b/assets/css/custom.css
index 789132e..e0187d8 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -1,403 +1,906 @@
+:root {
+ --bg: #f5f4f1;
+ --surface: #ffffff;
+ --surface-alt: #f8f7f4;
+ --line: #e7e5e4;
+ --line-strong: #d6d3d1;
+ --text: #171717;
+ --muted: #57534e;
+ --accent: #2b2927;
+ --accent-soft: #efeeea;
+ --success: #166534;
+ --warning: #92400e;
+ --danger: #991b1b;
+ --radius-sm: 8px;
+ --radius-md: 12px;
+ --radius-lg: 18px;
+ --shadow-sm: 0 1px 2px rgba(17, 24, 39, 0.04);
+ --shadow-md: 0 16px 40px -32px rgba(17, 24, 39, 0.5);
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
body {
- background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
- background-size: 400% 400%;
- animation: gradient 15s ease infinite;
- color: #212529;
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
- font-size: 14px;
margin: 0;
min-height: 100vh;
+ background: var(--bg);
+ color: var(--text);
+ font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
}
-.main-wrapper {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 100vh;
- width: 100%;
- padding: 20px;
- box-sizing: border-box;
- position: relative;
- z-index: 1;
+img {
+ max-width: 100%;
+ display: block;
}
-@keyframes gradient {
- 0% {
- background-position: 0% 50%;
- }
- 50% {
- background-position: 100% 50%;
- }
- 100% {
- background-position: 0% 50%;
- }
+strong {
+ font-weight: 600;
}
-.chat-container {
- width: 100%;
- max-width: 600px;
- background: rgba(255, 255, 255, 0.85);
- border: 1px solid rgba(255, 255, 255, 0.3);
- border-radius: 20px;
+small,
+.small {
+ color: var(--muted);
+}
+
+.text-muted {
+ color: var(--muted) !important;
+}
+
+a {
+ color: var(--text);
+ text-decoration: none;
+}
+
+.site-header {
+ background: rgba(245, 244, 241, 0.92);
+ border-bottom: 1px solid var(--line);
+ backdrop-filter: blur(12px);
+}
+
+.navbar {
+ padding: 0.875rem 0;
+}
+
+.navbar-toggler {
+ border-radius: var(--radius-sm);
+ border-color: var(--line-strong);
+}
+
+.navbar-toggler:focus {
+ box-shadow: 0 0 0 0.2rem rgba(23, 23, 23, 0.08);
+}
+
+.brand-mark {
+ display: flex;
+ flex-direction: column;
+ gap: 0.125rem;
+}
+
+.brand-mark__title {
+ font-size: 0.95rem;
+ font-weight: 700;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+}
+
+.brand-mark__subtitle {
+ font-size: 0.77rem;
+ color: var(--muted);
+}
+
+.nav-link {
+ color: var(--muted);
+ font-weight: 500;
+ border-radius: 999px;
+ padding: 0.5rem 0.875rem !important;
+}
+
+.nav-link:hover,
+.nav-link.active {
+ color: var(--text);
+ background: var(--surface);
+ box-shadow: inset 0 0 0 1px var(--line);
+}
+
+.btn,
+.form-control,
+textarea {
+ border-radius: var(--radius-sm);
+}
+
+.btn {
+ font-weight: 600;
+ padding: 0.75rem 1rem;
+}
+
+.btn:focus-visible,
+.form-control:focus-visible,
+textarea:focus-visible,
+.choice-card:focus-visible,
+.filter-pill:focus-visible {
+ outline: 2px solid rgba(23, 23, 23, 0.12);
+ outline-offset: 2px;
+}
+
+.btn-dark {
+ background: var(--accent);
+ border-color: var(--accent);
+}
+
+.btn-dark:hover,
+.btn-dark:focus {
+ background: #111111;
+ border-color: #111111;
+}
+
+.btn-outline-secondary {
+ color: var(--text);
+ border-color: var(--line-strong);
+ background: var(--surface);
+}
+
+.btn-outline-secondary:hover,
+.btn-outline-secondary:focus {
+ color: var(--text);
+ background: var(--surface-alt);
+ border-color: var(--text);
+}
+
+.btn-lg {
+ padding: 0.9rem 1.15rem;
+}
+
+.btn-cart {
+ box-shadow: var(--shadow-sm);
+}
+
+.form-control,
+textarea {
+ border: 1px solid var(--line-strong);
+ padding: 0.75rem 0.9rem;
+ background: var(--surface);
+}
+
+.form-control:focus,
+textarea:focus {
+ border-color: var(--text);
+ box-shadow: 0 0 0 0.2rem rgba(23, 23, 23, 0.08);
+}
+
+.invalid-feedback {
+ font-size: 0.85rem;
+}
+
+.site-main {
+ padding-bottom: 2rem;
+}
+
+.hero-panel,
+.surface-panel,
+.summary-card,
+.product-card,
+.metric-card,
+.feature-card,
+.step-card,
+.empty-state-card,
+.cart-item,
+.info-box,
+.choice-card {
+ background: var(--surface);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-sm);
+}
+
+.hero-panel {
+ padding: clamp(1.25rem, 2vw, 2.5rem);
+}
+
+.surface-panel,
+.summary-card,
+.feature-card,
+.step-card,
+.empty-state-card {
+ padding: 1.5rem;
+}
+
+.section-block {
+ padding: 1rem 0 2rem;
+}
+
+.eyebrow {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.4rem 0.65rem;
+ border-radius: 999px;
+ background: var(--accent-soft);
+ color: var(--muted);
+ font-size: 0.78rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+}
+
+.display-title {
+ font-size: clamp(2.25rem, 4vw, 4rem);
+ line-height: 1;
+ font-weight: 800;
+ letter-spacing: -0.04em;
+ margin: 1rem 0;
+ max-width: 12ch;
+}
+
+.lead-copy {
+ color: var(--muted);
+ max-width: 62ch;
+ font-size: 1.05rem;
+ line-height: 1.7;
+}
+
+.section-title {
+ font-size: clamp(1.65rem, 2.4vw, 2.5rem);
+ line-height: 1.1;
+ letter-spacing: -0.03em;
+ font-weight: 700;
+ margin: 0.65rem 0 0.75rem;
+}
+
+.section-copy {
+ color: var(--muted);
+ max-width: 60ch;
+ line-height: 1.7;
+}
+
+.metric-card {
+ padding: 1.1rem 1rem;
+ height: 100%;
+}
+
+.metric-value {
+ font-size: 1.6rem;
+ font-weight: 700;
+ letter-spacing: -0.03em;
+}
+
+.metric-value--small {
+ font-size: 1.2rem;
+}
+
+.metric-label {
+ margin-top: 0.4rem;
+ font-size: 0.88rem;
+ color: var(--muted);
+}
+
+.card-kicker {
+ font-size: 0.77rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--muted);
+ font-weight: 600;
+ margin-bottom: 0.6rem;
+}
+
+.summary-title {
+ font-size: 1.45rem;
+ font-weight: 700;
+ letter-spacing: -0.03em;
+ margin-bottom: 1rem;
+}
+
+.list-clean {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.compact-list {
+ display: grid;
+ gap: 0.85rem;
+}
+
+.compact-list li {
+ display: flex;
+ gap: 0.875rem;
+ align-items: flex-start;
+ color: var(--muted);
+}
+
+.list-index {
+ width: 1.75rem;
+ height: 1.75rem;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--accent-soft);
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ color: var(--text);
+ font-size: 0.82rem;
+ font-weight: 600;
+ flex-shrink: 0;
+}
+
+.receipt-card {
+ background: var(--surface-alt);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-md);
+ padding: 1rem 1.1rem;
+}
+
+.receipt-card--flat {
+ background: transparent;
+ padding: 0;
+ border: 0;
+}
+
+.receipt-card__head {
+ display: flex;
+ justify-content: space-between;
+ gap: 1rem;
+ font-size: 0.92rem;
+ color: var(--muted);
+ margin-bottom: 0.65rem;
+}
+
+.receipt-line {
+ display: flex;
+ justify-content: space-between;
+ gap: 1rem;
+ align-items: flex-start;
+ padding: 0.75rem 0;
+ border-top: 1px solid var(--line);
+ color: var(--muted);
+}
+
+.receipt-line:first-of-type {
+ border-top: 0;
+ padding-top: 0;
+}
+
+.receipt-line strong {
+ color: var(--text);
+ font-weight: 600;
+ text-align: right;
+}
+
+.receipt-line--total {
+ margin-top: 0.25rem;
+ padding-top: 1rem;
+ border-top: 1px solid var(--line-strong);
+ font-size: 1rem;
+}
+
+.feature-card__title,
+.step-card h3 {
+ font-size: 1.02rem;
+ font-weight: 700;
+ margin-bottom: 0.55rem;
+}
+
+.feature-card__copy,
+.step-card p,
+.note-copy,
+.info-box p {
+ color: var(--muted);
+ line-height: 1.7;
+ margin: 0;
+}
+
+.step-card__number {
+ font-size: 0.8rem;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin-bottom: 0.85rem;
+}
+
+.filter-pills {
+ overflow-x: auto;
+ padding-bottom: 0.125rem;
+}
+
+.filter-pill {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.65rem 0.95rem;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ background: var(--surface);
+ color: var(--muted);
+ font-size: 0.9rem;
+ white-space: nowrap;
+ transition: all 0.2s ease;
+}
+
+.filter-pill:hover,
+.filter-pill.is-active {
+ color: var(--text);
+ border-color: var(--text);
+}
+
+.product-card {
display: flex;
flex-direction: column;
- height: 85vh;
- box-shadow: 0 20px 40px rgba(0,0,0,0.2);
- backdrop-filter: blur(15px);
- -webkit-backdrop-filter: blur(15px);
overflow: hidden;
}
-.chat-header {
- padding: 1.5rem;
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
- background: rgba(255, 255, 255, 0.5);
- font-weight: 700;
- font-size: 1.1rem;
+.product-card__body {
display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding: 1.2rem;
+}
+
+.product-card__title {
+ font-size: 1.1rem;
+ font-weight: 700;
+ margin: 0;
+}
+
+.product-card__copy {
+ color: var(--muted);
+ line-height: 1.7;
+ margin-bottom: 1rem;
+}
+
+.product-visual {
+ border-bottom: 1px solid var(--line);
+ padding: 1.2rem;
+ min-height: 15rem;
+ display: flex;
+ flex-direction: column;
justify-content: space-between;
+ background: var(--surface-alt);
+}
+
+.product-visual--large {
+ min-height: 24rem;
+ border: 1px solid var(--line);
+ border-radius: calc(var(--radius-lg) - 4px);
+}
+
+.product-visual--mini {
+ min-height: 8.5rem;
+ width: 12rem;
+ border: 1px solid var(--line);
+ border-radius: var(--radius-md);
+ flex-shrink: 0;
+}
+
+.product-visual--ink {
+ background: #efefee;
+}
+
+.product-visual--stone {
+ background: #f4f2ee;
+}
+
+.product-visual--sand {
+ background: #f3efe6;
+}
+
+.product-visual--taupe {
+ background: #ece7df;
+}
+
+.product-visual__meta {
+ font-size: 0.78rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--muted);
+}
+
+.product-visual__code {
+ font-size: clamp(2.5rem, 6vw, 5rem);
+ letter-spacing: -0.08em;
+ line-height: 1;
+ font-weight: 800;
+ color: rgba(23, 23, 23, 0.85);
+}
+
+.product-visual__name {
+ font-size: 0.95rem;
+ color: var(--muted);
+}
+
+.price-tag {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0.45rem 0.75rem;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ font-weight: 600;
+ white-space: nowrap;
+ background: var(--surface-alt);
+}
+
+.price-tag--inline {
+ display: inline-flex;
+}
+
+.detail-chip-group {
+ display: flex;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+}
+
+.detail-chip {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.4rem 0.65rem;
+ background: var(--accent-soft);
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ font-size: 0.82rem;
+ color: var(--muted);
+}
+
+.sticky-summary {
+ position: sticky;
+ top: 6rem;
+}
+
+.breadcrumb {
+ --bs-breadcrumb-divider: '/';
+}
+
+.breadcrumb a {
+ color: var(--muted);
+}
+
+.breadcrumb-item.active {
+ color: var(--text);
+}
+
+.price-block__amount {
+ font-size: clamp(1.9rem, 4vw, 3rem);
+ font-weight: 800;
+ letter-spacing: -0.05em;
+}
+
+.price-block__caption {
+ color: var(--muted);
+ margin-top: 0.35rem;
+}
+
+.detail-grid {
+ display: grid;
+ gap: 0.85rem;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
+.detail-grid > div {
+ border: 1px solid var(--line);
+ border-radius: var(--radius-md);
+ padding: 0.9rem 1rem;
+ background: var(--surface-alt);
+}
+
+.detail-grid__label {
+ display: block;
+ font-size: 0.78rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--muted);
+ margin-bottom: 0.3rem;
+}
+
+.purchase-box {
+ padding: 1rem;
+ background: var(--surface-alt);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-md);
+}
+
+.quantity-field {
+ display: grid;
+ grid-template-columns: 48px minmax(84px, 110px) 48px;
+ gap: 0.75rem;
align-items: center;
}
-.chat-messages {
- flex: 1;
- overflow-y: auto;
- padding: 1.5rem;
+.quantity-field .btn {
+ padding: 0.55rem 0.75rem;
+}
+
+.quantity-field .form-control {
+ font-weight: 600;
+}
+
+.quantity-field--compact {
+ grid-template-columns: 40px 84px 40px;
+ gap: 0.5rem;
+}
+
+.section-divider {
+ height: 1px;
+ background: var(--line);
+ margin: 1.5rem 0;
+}
+
+.choice-card {
display: flex;
flex-direction: column;
- gap: 1.25rem;
+ gap: 0.35rem;
+ padding: 1rem;
+ height: 100%;
+ border-radius: var(--radius-md);
+ cursor: pointer;
+ transition: all 0.2s ease;
}
-/* Custom Scrollbar */
-::-webkit-scrollbar {
- width: 6px;
+.choice-title {
+ font-weight: 600;
+ color: var(--text);
}
-::-webkit-scrollbar-track {
- background: transparent;
+.choice-copy {
+ font-size: 0.9rem;
+ color: var(--muted);
+ line-height: 1.6;
}
-::-webkit-scrollbar-thumb {
- background: rgba(255, 255, 255, 0.3);
- border-radius: 10px;
+.btn-check:checked + .choice-card {
+ border-color: var(--text);
+ box-shadow: inset 0 0 0 1px var(--text);
+ background: var(--surface-alt);
}
-::-webkit-scrollbar-thumb:hover {
- background: rgba(255, 255, 255, 0.5);
+.empty-state-card {
+ padding: min(8vw, 3rem);
+ max-width: 52rem;
}
-.message {
- max-width: 85%;
- padding: 0.85rem 1.1rem;
- border-radius: 16px;
- line-height: 1.5;
- font-size: 0.95rem;
- box-shadow: 0 4px 15px rgba(0,0,0,0.05);
- animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
-}
-
-@keyframes fadeIn {
- from { opacity: 0; transform: translateY(20px) scale(0.95); }
- to { opacity: 1; transform: translateY(0) scale(1); }
-}
-
-.message.visitor {
- align-self: flex-end;
- background: linear-gradient(135deg, #212529 0%, #343a40 100%);
- color: #fff;
- border-bottom-right-radius: 4px;
-}
-
-.message.bot {
- align-self: flex-start;
- background: #ffffff;
- color: #212529;
- border-bottom-left-radius: 4px;
-}
-
-.chat-input-area {
- padding: 1.25rem;
- background: rgba(255, 255, 255, 0.5);
- border-top: 1px solid rgba(0, 0, 0, 0.05);
-}
-
-.chat-input-area form {
+.cart-item {
display: flex;
+ gap: 1rem;
+ padding: 1rem;
+}
+
+.cart-item__body {
+ flex: 1;
+}
+
+.cart-item__title {
+ font-size: 1.05rem;
+ margin: 0;
+ font-weight: 700;
+}
+
+.cart-item__total {
+ font-weight: 700;
+ font-size: 1rem;
+}
+
+.info-box {
+ padding: 1rem 1.1rem;
+ background: var(--surface-alt);
+ border-radius: var(--radius-md);
+}
+
+.order-table thead th {
+ font-size: 0.8rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--muted);
+ border-bottom: 1px solid var(--line);
+}
+
+.order-table tbody td,
+.order-table tfoot td {
+ border-bottom: 1px solid var(--line);
+ padding: 0.85rem 0;
+}
+
+.order-table tfoot tr:last-child td {
+ border-bottom: 0;
+ padding-bottom: 0;
+}
+
+.status-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4rem;
+ padding: 0.45rem 0.75rem;
+ border-radius: 999px;
+ font-size: 0.85rem;
+ font-weight: 600;
+ border: 1px solid var(--line);
+ background: var(--surface-alt);
+}
+
+.status-pill--pending {
+ background: #fff8eb;
+ border-color: #f3d28a;
+ color: #8a5a00;
+}
+
+.status-pill--processing {
+ background: #f4f4f5;
+ border-color: #d4d4d8;
+ color: #3f3f46;
+}
+
+.status-pill--shipping {
+ background: #eef2ff;
+ border-color: #c7d2fe;
+ color: #3730a3;
+}
+
+.status-pill--done {
+ background: #ecfdf3;
+ border-color: #bbf7d0;
+ color: #166534;
+}
+
+.status-pill--cancelled {
+ background: #fef2f2;
+ border-color: #fecaca;
+ color: #991b1b;
+}
+
+.status-legend {
+ display: grid;
gap: 0.75rem;
}
-.chat-input-area input {
- flex: 1;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 12px;
- padding: 0.75rem 1rem;
- outline: none;
- background: rgba(255, 255, 255, 0.9);
- transition: all 0.3s ease;
+.status-legend__item {
+ display: grid;
+ gap: 0.4rem;
}
-.chat-input-area input:focus {
- border-color: #23a6d5;
- box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2);
-}
-
-.chat-input-area button {
- background: #212529;
- color: #fff;
- border: none;
- padding: 0.75rem 1.5rem;
- border-radius: 12px;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.3s ease;
-}
-
-.chat-input-area button:hover {
- background: #000;
- transform: translateY(-2px);
- box-shadow: 0 5px 15px rgba(0,0,0,0.2);
-}
-
-/* Background Animations */
-.bg-animations {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 0;
- overflow: hidden;
- pointer-events: none;
-}
-
-.blob {
- position: absolute;
- width: 500px;
- height: 500px;
- background: rgba(255, 255, 255, 0.2);
- border-radius: 50%;
- filter: blur(80px);
- animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1);
-}
-
-.blob-1 {
- top: -10%;
- left: -10%;
- background: rgba(238, 119, 82, 0.4);
-}
-
-.blob-2 {
- bottom: -10%;
- right: -10%;
- background: rgba(35, 166, 213, 0.4);
- animation-delay: -7s;
- width: 600px;
- height: 600px;
-}
-
-.blob-3 {
- top: 40%;
- left: 30%;
- background: rgba(231, 60, 126, 0.3);
- animation-delay: -14s;
- width: 450px;
- height: 450px;
-}
-
-@keyframes move {
- 0% { transform: translate(0, 0) rotate(0deg) scale(1); }
- 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); }
- 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); }
- 100% { transform: translate(0, 0) rotate(360deg) scale(1); }
-}
-
-.header-link {
- font-size: 14px;
- color: #fff;
- text-decoration: none;
- background: rgba(0, 0, 0, 0.2);
- padding: 0.5rem 1rem;
- border-radius: 8px;
- transition: all 0.3s ease;
-}
-
-.header-link:hover {
- background: rgba(0, 0, 0, 0.4);
- text-decoration: none;
-}
-
-/* Admin Styles */
-.admin-container {
- max-width: 900px;
- margin: 3rem auto;
- padding: 2.5rem;
- background: rgba(255, 255, 255, 0.85);
- backdrop-filter: blur(20px);
- -webkit-backdrop-filter: blur(20px);
- border-radius: 24px;
- box-shadow: 0 20px 50px rgba(0,0,0,0.15);
- border: 1px solid rgba(255, 255, 255, 0.4);
- position: relative;
- z-index: 1;
-}
-
-.admin-container h1 {
- margin-top: 0;
- color: #212529;
- font-weight: 800;
-}
-
-.table {
- width: 100%;
- border-collapse: separate;
- border-spacing: 0 8px;
- margin-top: 1.5rem;
-}
-
-.table th {
- background: transparent;
- border: none;
- padding: 1rem;
- color: #6c757d;
- font-weight: 600;
- text-transform: uppercase;
- font-size: 0.75rem;
- letter-spacing: 1px;
-}
-
-.table td {
- background: #fff;
- padding: 1rem;
- border: none;
-}
-
-.table tr td:first-child { border-radius: 12px 0 0 12px; }
-.table tr td:last-child { border-radius: 0 12px 12px 0; }
-
-.form-group {
- margin-bottom: 1.25rem;
-}
-
-.form-group label {
- display: block;
- margin-bottom: 0.5rem;
- font-weight: 600;
- font-size: 0.9rem;
-}
-
-.form-control {
- width: 100%;
- padding: 0.75rem 1rem;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 12px;
- background: #fff;
- transition: all 0.3s ease;
- box-sizing: border-box;
-}
-
-.form-control:focus {
- outline: none;
- border-color: #23a6d5;
- box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1);
-}
-
-.header-container {
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.header-links {
- display: flex;
+.timeline-list {
+ display: grid;
gap: 1rem;
}
-.admin-card {
- background: rgba(255, 255, 255, 0.6);
- padding: 2rem;
- border-radius: 20px;
- border: 1px solid rgba(255, 255, 255, 0.5);
- margin-bottom: 2.5rem;
- box-shadow: 0 10px 30px rgba(0,0,0,0.05);
-}
-
-.admin-card h3 {
- margin-top: 0;
- margin-bottom: 1.5rem;
- font-weight: 700;
-}
-
-.btn-delete {
- background: #dc3545;
- color: white;
- border: none;
- padding: 0.25rem 0.5rem;
- border-radius: 4px;
- cursor: pointer;
-}
-
-.btn-add {
- background: #212529;
- color: white;
- border: none;
- padding: 0.5rem 1rem;
- border-radius: 4px;
- cursor: pointer;
- margin-top: 1rem;
-}
-
-.btn-save {
- background: #0088cc;
- color: white;
- border: none;
- padding: 0.8rem 1.5rem;
- border-radius: 12px;
- cursor: pointer;
- font-weight: 600;
- width: 100%;
- transition: all 0.3s ease;
-}
-
-.webhook-url {
- font-size: 0.85em;
- color: #555;
- margin-top: 0.5rem;
-}
-
-.history-table-container {
- overflow-x: auto;
- background: rgba(255, 255, 255, 0.4);
+.timeline-step {
+ display: flex;
+ gap: 1rem;
padding: 1rem;
- border-radius: 12px;
- border: 1px solid rgba(255, 255, 255, 0.3);
+ border: 1px solid var(--line);
+ border-radius: var(--radius-md);
+ background: var(--surface-alt);
+ opacity: 0.72;
}
-.history-table {
- width: 100%;
+.timeline-step__dot {
+ width: 0.9rem;
+ height: 0.9rem;
+ margin-top: 0.35rem;
+ border-radius: 999px;
+ background: var(--line-strong);
+ flex-shrink: 0;
}
-.history-table-time {
- width: 15%;
- white-space: nowrap;
- font-size: 0.85em;
- color: #555;
+.timeline-step__title {
+ font-weight: 600;
+ margin-bottom: 0.25rem;
}
-.history-table-user {
- width: 35%;
- background: rgba(255, 255, 255, 0.3);
- border-radius: 8px;
- padding: 8px;
+.timeline-step__copy {
+ color: var(--muted);
+ line-height: 1.6;
}
-.history-table-ai {
- width: 50%;
- background: rgba(255, 255, 255, 0.5);
- border-radius: 8px;
- padding: 8px;
+.timeline-step.is-complete,
+.timeline-step.is-current {
+ opacity: 1;
+ border-color: var(--line-strong);
}
-.no-messages {
- text-align: center;
- color: #777;
-}
\ No newline at end of file
+.timeline-step.is-complete .timeline-step__dot {
+ background: var(--success);
+}
+
+.timeline-step.is-current .timeline-step__dot {
+ background: var(--accent);
+ box-shadow: 0 0 0 4px rgba(23, 23, 23, 0.08);
+}
+
+.toast-stack {
+ z-index: 1080;
+}
+
+.toast-theme {
+ background: rgba(23, 23, 23, 0.96);
+ color: #ffffff;
+ border: 0;
+ border-radius: var(--radius-md);
+ box-shadow: var(--shadow-md);
+}
+
+.toast-theme--success {
+ background: rgba(22, 101, 52, 0.96);
+}
+
+.toast-theme--warning {
+ background: rgba(146, 64, 14, 0.96);
+}
+
+.toast-theme--danger {
+ background: rgba(153, 27, 27, 0.96);
+}
+
+.site-footer {
+ border-top: 1px solid var(--line);
+ background: rgba(255, 255, 255, 0.7);
+}
+
+.footer-title {
+ font-size: 0.95rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ margin-bottom: 0.35rem;
+}
+
+.footer-copy {
+ color: var(--muted);
+ margin: 0;
+ max-width: 36rem;
+ line-height: 1.6;
+}
+
+.footer-links a {
+ color: var(--muted);
+ font-weight: 500;
+}
+
+.footer-links a:hover {
+ color: var(--text);
+}
+
+.alert {
+ border-radius: var(--radius-md);
+}
+
+@media (max-width: 991.98px) {
+ .sticky-summary {
+ position: static;
+ }
+
+ .product-visual--mini {
+ width: 100%;
+ min-height: 10rem;
+ }
+}
+
+@media (max-width: 767.98px) {
+ .hero-panel,
+ .surface-panel,
+ .summary-card,
+ .feature-card,
+ .step-card,
+ .empty-state-card,
+ .cart-item,
+ .product-card__body {
+ padding: 1rem;
+ }
+
+ .display-title {
+ max-width: none;
+ }
+
+ .detail-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .cart-item {
+ flex-direction: column;
+ }
+
+ .quantity-field {
+ grid-template-columns: 44px minmax(72px, 1fr) 44px;
+ }
+}
diff --git a/assets/js/main.js b/assets/js/main.js
index d349598..a11200a 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,39 +1,63 @@
document.addEventListener('DOMContentLoaded', () => {
- const chatForm = document.getElementById('chat-form');
- const chatInput = document.getElementById('chat-input');
- const chatMessages = document.getElementById('chat-messages');
+ if (window.bootstrap && window.bootstrap.Toast) {
+ document.querySelectorAll('.toast').forEach((element) => {
+ const toast = new window.bootstrap.Toast(element);
+ toast.show();
+ });
+ }
- const appendMessage = (text, sender) => {
- const msgDiv = document.createElement('div');
- msgDiv.classList.add('message', sender);
- msgDiv.textContent = text;
- chatMessages.appendChild(msgDiv);
- chatMessages.scrollTop = chatMessages.scrollHeight;
- };
+ document.querySelectorAll('[data-qty-target][data-qty-step]').forEach((button) => {
+ button.addEventListener('click', () => {
+ const targetId = button.getAttribute('data-qty-target');
+ const input = targetId ? document.getElementById(targetId) : null;
+ if (!input) {
+ return;
+ }
- chatForm.addEventListener('submit', async (e) => {
- e.preventDefault();
- const message = chatInput.value.trim();
- if (!message) return;
+ const min = parseInt(input.getAttribute('min') || '1', 10);
+ const max = parseInt(input.getAttribute('max') || '20', 10);
+ const step = parseInt(button.getAttribute('data-qty-step') || '0', 10);
+ const current = parseInt(input.value || String(min), 10) || min;
+ const next = Math.max(min, Math.min(max, current + step));
+ input.value = String(next);
+ input.dispatchEvent(new Event('change', { bubbles: true }));
+ });
+ });
- appendMessage(message, 'visitor');
- chatInput.value = '';
+ document.querySelectorAll('[data-copy-text]').forEach((button) => {
+ button.addEventListener('click', async () => {
+ const value = button.getAttribute('data-copy-text');
+ if (!value || !navigator.clipboard) {
+ return;
+ }
- try {
- const response = await fetch('api/chat.php', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ message })
- });
- const data = await response.json();
-
- // Artificial delay for realism
- setTimeout(() => {
- appendMessage(data.reply, 'bot');
- }, 500);
- } catch (error) {
- console.error('Error:', error);
- appendMessage("Sorry, something went wrong. Please try again.", 'bot');
- }
+ const originalText = button.textContent;
+ try {
+ await navigator.clipboard.writeText(value);
+ button.textContent = 'Tersalin';
+ button.classList.remove('btn-outline-success');
+ button.classList.add('btn-success');
+ window.setTimeout(() => {
+ button.textContent = originalText;
+ button.classList.remove('btn-success');
+ button.classList.add('btn-outline-success');
+ }, 1500);
+ } catch (error) {
+ console.error('Clipboard error', error);
+ }
+ });
+ });
+
+ document.querySelectorAll('[data-auto-disable]').forEach((form) => {
+ form.addEventListener('submit', () => {
+ const submitButton = form.querySelector('button[type="submit"]');
+ if (!submitButton || submitButton.disabled) {
+ return;
+ }
+
+ submitButton.dataset.originalText = submitButton.innerHTML;
+ submitButton.disabled = true;
+ submitButton.innerHTML = 'Memproses…';
+ });
});
});
diff --git a/cart.php b/cart.php
new file mode 100644
index 0000000..fe77039
--- /dev/null
+++ b/cart.php
@@ -0,0 +1,110 @@
+ true]);
+?>
+ Update quantity, cek ongkir, lalu lanjut ke checkout untuk menyimpan pesanan ke sistem. Mulai dari katalog untuk mencoba alur add-to-cart lalu kembali ke halaman ini. Status awal pesanan adalah Menunggu Pembayaran. Instruksi pembayaran akan tampil setelah order berhasil dibuat.Tinjau pesanan sebelum checkout.
+ Belum ada produk di keranjang.
+ Simpan pesanan ke sistem.
+
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-This page will update automatically as the plan is implemented.
-Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
+ Katalog, keranjang, checkout, dan halaman status pesanan sekarang terhubung dalam satu alur yang rapi. + Cocok untuk validasi toko online berbasis PHP + MySQL sebelum lanjut ke admin panel penuh. +
+ +Ada kategori, harga, deskripsi singkat, dan halaman detail produk untuk tiap item.
+Order number dibuat otomatis, item pesanan disimpan di MySQL, dan status awal langsung tercatat.
+Pelanggan cukup masukkan kode pesanan dan email untuk melihat progress dan instruksi pembayaran.
+Gunakan katalog ini sebagai starting point sebelum menambahkan admin, stok, kupon, dan pembayaran real.
+= h($product['lead_time']) ?>
+= h($product['short_description']) ?>
+Pelanggan lihat katalog, buka detail produk, lalu tambahkan item ke keranjang.
+Isi nama, email, telepon, alamat, dan metode pembayaran. Order number dibuat otomatis.
+Gunakan order number dan email untuk melihat status pesanan dan instruksi pembayaran kapan saja.
+Masukkan kode pesanan dan email untuk melihat item, total, metode pembayaran, dan status terbaru.
+Dibuat pada = h(store_format_datetime((string)$order['created_at'])) ?>
+| Produk | +Qty | +Total | +
|---|---|---|
|
+ = h((string)$item['name']) ?>
+ = h(store_money((float)$item['price'])) ?> / item
+ |
+ = h((string)$item['quantity']) ?> | += h(store_money((float)$item['line_total'])) ?> | +
| Subtotal | += h(store_money((float)$order['subtotal'])) ?> | +|
| Ongkir | += h(store_money((float)$order['shipping_fee'])) ?> | +|
| Grand total | += h(store_money((float)$order['grand_total'])) ?> | +|
= h((string)$order['customer_name']) ?>
+= h((string)$order['email']) ?>
+= h((string)$order['phone']) ?>
+= nl2br(h((string)$order['address'])) ?>
+= h((string)$order['payment_instruction']) ?>
+ += h($step['description']) ?>
+Setelah checkout berhasil, halaman ini akan menampilkan ringkasan item, total pembayaran, dan progress status order.
+Slug produk tidak valid atau item sudah dihapus dari katalog demo.
+ += h($product['description']) ?>
+Saat checkout, pelanggan akan memilih metode pembayaran dan sistem langsung membuat order number untuk pelacakan status.
+= h($related['short_description']) ?>
+ Buka detail +