/* ========================================================== Project modal: behaviour and state only. Visual styling (type, colour, padding, borders) lives in Webflow Designer. Selectors use data attributes so class renames never break this file. ========================================================== */ html [data-modal="project"] { position: fixed; inset: 0; z-index: 1000; /* above nav (500) and contact card (400) */ display: flex; align-items: center; justify-content: center; padding: 24px; visibility: hidden; pointer-events: none; } html [data-modal="project"].is-open { visibility: visible; pointer-events: auto; } /* Blurred page behind the panel */ html [data-modal="project"] [data-modal-backdrop] { position: absolute; inset: 0; background-color: rgba(10, 10, 12, 0.45); -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); opacity: 0; visibility: hidden; } /* Centred panel. Change max-width here to resize it. */ html [data-modal="project"] [data-modal-panel] { position: relative; width: 100%; max-width: 640px; max-height: calc(100vh - 48px); /* fallback for browsers without dvh */ max-height: calc(100dvh - 48px); display: flex; flex-direction: column; opacity: 0; visibility: hidden; outline: none; } html [data-modal="project"] [data-modal-header] { flex: none; } /* Scroll area for short viewports. Header stays fixed above it. */ html [data-modal="project"] [data-modal-body] { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; } html [data-modal="project"] textarea { overscroll-behavior: contain; } /* Hairline under the header that fills as required fields are completed */ html [data-modal="project"] [data-modal-progress] { transform-origin: left center; transform: scaleX(0); transition: transform 600ms cubic-bezier(0.16, 1, 0.3, 1); } /* ---------- Service chips (Webflow Radio Button elements) ---------- */ html [data-modal="project"] [data-chip] { position: relative; cursor: pointer; transition: background-color 180ms cubic-bezier(0.16, 1, 0.3, 1), color 180ms cubic-bezier(0.16, 1, 0.3, 1); } /* Hide the native radio but keep it clickable and focusable */ html [data-modal="project"] [data-chip] input[type="radio"] { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; } html [data-modal="project"] [data-chip]:has(input:checked) { background-color: #fafafa; /* site light */ color: #282828; /* site dark */ } html [data-modal="project"] [data-chip]:has(input:focus-visible) { outline: 1px solid rgba(250, 250, 250, 0.6); outline-offset: 2px; } /* ---------- Mobile: sheet anchored to the bottom ---------- */ /* --vv-* values come from the JS (visualViewport), so the sheet shrinks to sit above the on-screen keyboard instead of under it. */ @media (max-width: 767px) { html [data-modal="project"] { top: var(--vv-top, 0px); bottom: auto; height: 100vh; height: var(--vv-height, 100dvh); align-items: flex-end; padding: 12px; } html [data-modal="project"] [data-modal-panel] { max-width: none; max-height: calc(100vh - 24px); max-height: calc(var(--vv-height, 100dvh) - 24px); } /* Full-screen blur is expensive on low-end Android. Less blur, more tint. */ html [data-modal="project"] [data-modal-backdrop] { background-color: rgba(10, 10, 12, 0.6); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); } } /* Browsers without backdrop-filter get a solid tint instead */ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { html [data-modal="project"] [data-modal-backdrop] { background-color: rgba(10, 10, 12, 0.88); } } /* ---------- Page state while open ---------- */ /* Swap in your pixel trail canvas selector. Stops the trail smearing underneath the blur while the modal is open. */ html.is-modal-open [data-pixel-trail] { opacity: 0; transition: opacity 180ms linear; } @media (prefers-reduced-motion: reduce) { html [data-modal="project"] [data-modal-progress], html [data-modal="project"] [data-chip] { transition-duration: 200ms; } }