/* ============================================================
WorkStay — Property Detail (luxury architecture presentation)
exports: PropertyPage, OperatorPage
============================================================ */
const { useState: useStatePr, useEffect: useEffectPr } = React;
function PropertyPage({ go, params = {}, wish = [], toggleWish }) {
const { PROPERTIES, OPERATORS, REVIEWS, AI_SUMMARY } = window.WS_DATA;
const p = PROPERTIES.find(x => x.id === params.id) || PROPERTIES[0];
const op = OPERATORS[p.operator];
const wished = wish.includes(p.id);
const m = p.metrics;
return (
{/* ---------- edge-to-edge gallery ---------- */}
{/* floating title */}
Deep Work Certified
{p.collection}
{p.name}
{p.city}, {p.country}
{p.beds} bd · {p.baths} ba · {p.sqm} m²
{op.rating} · {REVIEWS.length * 14} stays
toggleWish(p.id)} style={wished ? { borderColor: 'var(--violet)', color: 'var(--violet-soft)' } : {}}>{wished ? 'Saved' : 'Save'}
{/* ---------- body: content + sticky booking ---------- */}
{p.tagline}
Built and maintained by {op.name}, every detail here is tuned for the rhythm of focused work — from the wired desk to the silence that settles in after dark.
{/* Workspace Intelligence */}
{/* Natural light timeline */}
{/* Daily noise timeline */}
{/* amenities */}
{p.amenities.map(a => (
{a}
))}
{/* operator strip */}
go('operator', { id: op.id })} style={{ width: '100%', textAlign: 'left', marginTop: 56, padding: 26, borderRadius: 'var(--r-lg)', background: 'var(--surface)', border: '1px solid var(--line)', display: 'flex', gap: 18, alignItems: 'center', transition: 'border-color .3s' }}
onMouseEnter={e => e.currentTarget.style.borderColor = 'var(--line-2)'} onMouseLeave={e => e.currentTarget.style.borderColor = 'var(--line)'}>
{op.initials}
Operated by
{op.name}
“{op.philosophy}”
{/* reviews */}
AI review summary
{AI_SUMMARY}
{REVIEWS.map(r => (
{r.tag}
“{r.body}”
{r.who} · {r.role}
))}
{/* sticky booking card */}
);
}
function WiCard({ icon, big, unit, label, tone, note }) {
const col = tone === 'good' ? 'var(--good)' : 'var(--violet-soft)';
return (
{big}
{unit}
{label}
{note}
);
}
/* natural light simulation across the day */
function LightTimeline() {
const [hour, setHour] = useStatePr(13);
const warmth = Math.max(0, 1 - Math.abs(hour - 13) / 9);
const sunX = ((hour - 6) / 12) * 100;
const sunY = 80 - Math.sin(((hour - 6) / 12) * Math.PI) * 64;
return (
{/* sun */}
{/* room light beam */}
{/* window frame silhouette */}
{hour > 12 ? `${hour === 12 ? 12 : hour - 12}:00 PM` : `${hour}:00 AM`} · {warmth > 0.6 ? 'Bright' : warmth > 0.3 ? 'Soft' : 'Dim'}
setHour(+e.target.value)} className="ws-range" style={{ width: '100%', marginTop: 18 }} />
6 AM Noon 8 PM
);
}
function NoiseTimeline({ quiet }) {
const noise = [40, 38, 35, 32, 36, 42, 44, 40, 34, 30, 26, 23, 21, 20, 22];
return (
{noise.map((n, i) => {
const h = ((n - 16) / 30) * 100;
const calm = n <= 26;
return
;
})}
6 AM Noon 6 PM Midnight
Deep-focus quiet
Ambient
);
}
/* ---------------- Operator profile page ---------------- */
function OperatorPage({ go, params = {} }) {
const { OPERATORS, PROPERTIES } = window.WS_DATA;
const op = OPERATORS[params.id] || OPERATORS.atlas;
const props = PROPERTIES.filter(p => p.operator === op.id);
const stats = [['Spaces', op.properties], ['Rating', op.rating], ['Reviews', op.reviews], ['Since', op.since]];
return (
{op.initials}
{op.name}
Verified Operator
{op.location}
“{op.philosophy}”
{stats.map(([l, v]) => (
))}
Workspace standards
{op.standards.map(s => (
{s}
))}
{props.map(p => (
go('property', { id: p.id })} style={{ position: 'relative', border: '1px solid var(--line)', borderRadius: 'var(--r-lg)', overflow: 'hidden', height: 300, padding: 0, textAlign: 'left', background: 'none' }}>
{p.name}
{p.city} · ${p.price.toLocaleString()}/mo
))}
);
}
Object.assign(window, { PropertyPage, OperatorPage });