feat: surface Guanghu era time authority
This commit is contained in:
parent
a96c5955bb
commit
3294447dce
8 changed files with 733 additions and 23 deletions
|
|
@ -63,6 +63,7 @@ interface HomeStatus {
|
|||
mcpRole: string
|
||||
}
|
||||
interface PersonalChannelIdentity { humanSubjectId: string; displayName: string; channelId: string; createdAtUnixMs: number }
|
||||
interface PersonalChannelModule { moduleId: string; kind: string; displayName: string; state: string; installedAtUnixMs: number; timeZone: string; calendarName: string; clockVerification: string }
|
||||
interface LoginSession { username: string; host: string; domain: string; signedInAtUnixMs: number }
|
||||
interface LoginReceipt { username: string; email: string; host: string; domain: string }
|
||||
interface UserPnccChannelSnapshot {
|
||||
|
|
@ -86,7 +87,11 @@ interface UserPnccChannelSnapshot {
|
|||
authority: string
|
||||
}
|
||||
interface PersonalChannelEvent { sequence: number; eventId: string; kind: string; summary: string; occurredAtUnixMs: number; receiptId: string; receiptHash: string }
|
||||
interface PersonalChannelSnapshot { state: string; identity?: PersonalChannelIdentity; recentEvents: PersonalChannelEvent[]; integrity: { state: string; eventCount: number; receiptCount: number } }
|
||||
interface PersonalChannelSnapshot { state: string; identity?: PersonalChannelIdentity; recentEvents: PersonalChannelEvent[]; modules: PersonalChannelModule[]; integrity: { state: string; eventCount: number; receiptCount: number } }
|
||||
interface BeijingTimeCoordinate { unixMs: number; beijingTime: string; timeZone: string; clockSource: string; clockVerification: string; networkSyncState: string; networkSynchronizedAtUnixMs?: number; networkUncertaintyMs?: number; continuesWhileHololakeIsClosed: boolean; guanghuEpochDate: string; guanghuEraDay: number; historicalEpochPrecision: string }
|
||||
interface PersonaTimeAuthorityStartup { state: string; synchronizationAttempted: boolean; networkTimeUrl: string; coordinate: BeijingTimeCoordinate }
|
||||
interface GuanghuEraEvent { eventId: string; displayDate: string; datePrecision: string; title: string; summary: string; evidenceState: string; sourceRecord: string }
|
||||
interface GuanghuEraTimeline { state: string; eraName: string; calendarName: string; epochDate: string; epochPrecision: string; publicRealityBoundary: string; currentCoordinate: BeijingTimeCoordinate; events: GuanghuEraEvent[] }
|
||||
interface KnowledgeDocumentSummary {
|
||||
source: KnowledgeSource
|
||||
path: string
|
||||
|
|
@ -262,7 +267,7 @@ interface EnterpriseReceiptEnvelope {
|
|||
}
|
||||
|
||||
const previewStatus: HomeStatus = { directLocalBrokerState: 'UNVERIFIED', directConnectionCount: 0, resumableSessionCount: 0, codeRepositoryMountCount: 0, pnccReceiptCount: 0, updateState: 'READY_HUMAN_CONFIRMATION_REQUIRED', releaseRecoveryState: 'NONE', mcpRole: 'DISCOVERY_RECOVERY_COMPATIBILITY_ONLY' }
|
||||
const previewPersonal: PersonalChannelSnapshot = { state: 'UNAVAILABLE', recentEvents: [], integrity: { state: 'UNKNOWN', eventCount: 0, receiptCount: 0 } }
|
||||
const previewPersonal: PersonalChannelSnapshot = { state: 'UNAVAILABLE', recentEvents: [], modules: [], integrity: { state: 'UNKNOWN', eventCount: 0, receiptCount: 0 } }
|
||||
const previewKnowledge: KnowledgeSnapshot = { state: 'UNAVAILABLE', nativeRoot: '', legacyAvailable: false, documents: [], rawDocumentCount: 0, uniqueDocumentCount: 0, duplicateDocumentCount: 0, truncated: false }
|
||||
const previewCode: CodeChannelSnapshot = { state: 'UNAVAILABLE', channels: [], authority: 'LOCAL_SOURCE_ACCESS_ONLY_NO_PUSH_OR_DEPLOY_AUTHORITY' }
|
||||
const themes: Array<{ id: ThemeId; name: string }> = [
|
||||
|
|
@ -320,6 +325,36 @@ function LakePool({ className, title, meta, open = false, risen = false, onClick
|
|||
</button>
|
||||
}
|
||||
|
||||
function displayBeijingTime(coordinate: BeijingTimeCoordinate | null): string {
|
||||
if (!coordinate) return '正在读取北京时间'
|
||||
return coordinate.beijingTime.replace('T', ' ').slice(0, 23)
|
||||
}
|
||||
|
||||
function EraHomeEntry({ timeline, coordinate, onOpen }: { timeline: GuanghuEraTimeline | null; coordinate: BeijingTimeCoordinate | null; onOpen: () => void }) {
|
||||
const markers = timeline ? [timeline.events[0], timeline.events[3], timeline.events[6], timeline.events[timeline.events.length - 1]].filter(Boolean) : []
|
||||
return <button className="era-home-entry" type="button" onClick={onOpen} aria-label="展开曜冥纪元演化时间线">
|
||||
<span className="era-home-heading"><b>曜冥纪元</b><small>{coordinate ? `光湖历第 ${coordinate.guanghuEraDay} 天` : '从 2025-04-26 起'}</small></span>
|
||||
<span className="era-home-markers" aria-hidden="true">{markers.map((event) => <i key={event.eventId}><em/>{event.displayDate.slice(0, 7)}</i>)}</span>
|
||||
<span className="era-home-now">{displayBeijingTime(coordinate)} · 查看演化史</span>
|
||||
</button>
|
||||
}
|
||||
|
||||
function EraTimelineOverlay({ timeline, coordinate, onClose }: { timeline: GuanghuEraTimeline; coordinate: BeijingTimeCoordinate | null; onClose: () => void }) {
|
||||
const activeCoordinate = coordinate ?? timeline.currentCoordinate
|
||||
const networkSynchronized = activeCoordinate.networkSyncState === 'SYNCHRONIZED_ON_APPLICATION_OPEN'
|
||||
return <div className="era-overlay" role="dialog" aria-modal="true" aria-label="曜冥纪元演化史">
|
||||
<button className="era-overlay-scrim" type="button" aria-label="关闭曜冥纪元" onClick={onClose}/>
|
||||
<section className="era-timeline-panel">
|
||||
<header><div><span>YAOMING ERA · HOLOLAKE CALENDAR</span><h2>{timeline.eraName}</h2><p>{timeline.calendarName}第 {activeCoordinate.guanghuEraDay} 天 · {displayBeijingTime(activeCoordinate)}</p></div><button type="button" aria-label="关闭" onClick={onClose}>×</button></header>
|
||||
<p className="era-clock-boundary">{networkSynchronized ? `HoloLake 打开时已通过加密网络读取现实时间锚点${activeCoordinate.networkUncertaintyMs ? `,当前估计误差不超过约 ${activeCoordinate.networkUncertaintyMs} 毫秒` : ''}。` : '联网校时尚未完成,当前暂用本机现实系统时钟并明确标记等待同步。'} HoloLake 关闭后,现实时间仍继续。</p>
|
||||
<ol>{timeline.events.map((event) => <li key={event.eventId}>
|
||||
<time>{event.displayDate}</time><i aria-hidden="true"/><div><h3>{event.title}</h3><p>{event.summary}</p></div>
|
||||
</li>)}</ol>
|
||||
<footer>源点精度:只确认到 2025-04-26 当日,具体时分秒未知。公众时间线只呈现现实可成立的演化事实;语言世界内部模拟不构成外部现实关系。</footer>
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
|
||||
function getOrCreateLocalId(key: string, prefix: string) {
|
||||
const existing = window.localStorage.getItem(key)
|
||||
if (existing) return existing
|
||||
|
|
@ -448,6 +483,15 @@ function HoloLakeApp() {
|
|||
const [toolReturnStage, setToolReturnStage] = useState<WorldStage>('channel')
|
||||
const [status, setStatus] = useState<HomeStatus>(previewStatus)
|
||||
const [personal, setPersonal] = useState<PersonalChannelSnapshot>(previewPersonal)
|
||||
const [eraTimeline, setEraTimeline] = useState<GuanghuEraTimeline | null>(null)
|
||||
const [beijingCoordinate, setBeijingCoordinate] = useState<BeijingTimeCoordinate | null>(null)
|
||||
const [eraOpen, setEraOpen] = useState(false)
|
||||
const openEraTimeline = useCallback(() => {
|
||||
setEraOpen(true)
|
||||
invoke<PersonaTimeAuthorityStartup>('start_persona_time_authority')
|
||||
.then((startup) => setBeijingCoordinate(startup.coordinate))
|
||||
.catch(() => undefined)
|
||||
}, [])
|
||||
const [knowledge, setKnowledge] = useState<KnowledgeSnapshot>(previewKnowledge)
|
||||
const [codeChannels, setCodeChannels] = useState<CodeChannelSnapshot>(previewCode)
|
||||
const [activeDocument, setActiveDocument] = useState<KnowledgeDocument | null>(null)
|
||||
|
|
@ -552,16 +596,25 @@ function HoloLakeApp() {
|
|||
}, [])
|
||||
|
||||
const refreshCore = useCallback(async () => {
|
||||
const [homeResult, personalResult, knowledgeResult, codeResult] = await Promise.allSettled([
|
||||
try {
|
||||
const startup = await invoke<PersonaTimeAuthorityStartup>('start_persona_time_authority')
|
||||
setBeijingCoordinate(startup.coordinate)
|
||||
} catch { /* 联网失败时其余首页能力仍可启动。 */ }
|
||||
const [homeResult, personalResult, knowledgeResult, codeResult, eraResult] = await Promise.allSettled([
|
||||
invoke<HomeStatus>('get_hololake_home_status'),
|
||||
invoke<PersonalChannelSnapshot>('get_personal_channel_snapshot'),
|
||||
invoke<KnowledgeSnapshot>('get_knowledge_snapshot'),
|
||||
invoke<CodeChannelSnapshot>('get_code_channel_snapshot'),
|
||||
invoke<GuanghuEraTimeline>('get_guanghu_era_timeline'),
|
||||
])
|
||||
if (homeResult.status === 'fulfilled') setStatus(homeResult.value)
|
||||
if (personalResult.status === 'fulfilled') setPersonal(personalResult.value)
|
||||
if (knowledgeResult.status === 'fulfilled') setKnowledge(knowledgeResult.value)
|
||||
if (codeResult.status === 'fulfilled') setCodeChannels(codeResult.value)
|
||||
if (eraResult.status === 'fulfilled') {
|
||||
setEraTimeline(eraResult.value)
|
||||
setBeijingCoordinate(eraResult.value.currentCoordinate)
|
||||
}
|
||||
}, [])
|
||||
const loadReceipts = useCallback(async () => {
|
||||
try {
|
||||
|
|
@ -575,6 +628,12 @@ function HoloLakeApp() {
|
|||
window.addEventListener('focus', refreshWhenHumanReturns)
|
||||
return () => window.removeEventListener('focus', refreshWhenHumanReturns)
|
||||
}, [refreshCore])
|
||||
useEffect(() => {
|
||||
if (!eraOpen) return
|
||||
const closeOnEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') setEraOpen(false) }
|
||||
window.addEventListener('keydown', closeOnEscape)
|
||||
return () => window.removeEventListener('keydown', closeOnEscape)
|
||||
}, [eraOpen])
|
||||
useEffect(() => {
|
||||
invoke<NearbyAiDiscoverySnapshot>('get_nearby_ai_discovery')
|
||||
.then(setNearbyDiscovery)
|
||||
|
|
@ -734,6 +793,7 @@ function HoloLakeApp() {
|
|||
: status.resumableSessionCount > 0
|
||||
? '原生会话可续接 · 当前离线'
|
||||
: '原生接口已驻留 · 尚无客户端'
|
||||
const timeAuthorityModule = personal.modules.find((module) => module.kind === 'PERSONA_TIME_AUTHORITY')
|
||||
|
||||
const openDocument = async (source: KnowledgeSource, path: string) => {
|
||||
setKnowledgeBusy(true)
|
||||
|
|
@ -1124,6 +1184,12 @@ function HoloLakeApp() {
|
|||
<button className="metric-panel" type="button" onClick={() => setView('code')}><span>代码频道</span><strong>{codeChannels.channels.length}</strong><small>可浏览、可转译、本机只读接入</small></button>
|
||||
<button className="metric-panel" type="button" onClick={() => setView('receipts')}><span>可核验回执</span><strong>{personal.integrity.receiptCount + status.pnccReceiptCount}</strong><small>身份、知识与代码证据</small></button>
|
||||
</div>
|
||||
{timeAuthorityModule && <button className="time-module-strip" type="button" onClick={openEraTimeline}>
|
||||
<span><i/><b>{timeAuthorityModule.displayName}</b><small>初始化频道内置模块 · {timeAuthorityModule.calendarName}</small></span>
|
||||
<strong>{beijingCoordinate ? `第 ${beijingCoordinate.guanghuEraDay} 天` : '时间正在流动'}</strong>
|
||||
<time>{displayBeijingTime(beijingCoordinate)}</time>
|
||||
<em>{beijingCoordinate?.networkSyncState === 'SYNCHRONIZED_ON_APPLICATION_OPEN' ? '打开软件时已联网校时' : '本机现实时间 · 等待联网校时'}</em>
|
||||
</button>}
|
||||
<div className="overview-columns">
|
||||
<section className="plain-panel recent-panel">
|
||||
<header><div><h2>最近知识</h2><p>从真实页面继续阅读</p></div><button type="button" onClick={() => setView('knowledge')}>打开工作台</button></header>
|
||||
|
|
@ -1362,8 +1428,10 @@ function HoloLakeApp() {
|
|||
<button className="gate-back" type="button" onClick={() => { setGateStage('number'); setGateMessage(''); setLoginMessage('') }}>返回编号验证</button>
|
||||
</section>
|
||||
</>}
|
||||
{gateStage === 'number' && !gateOpen && !activeDomainInfo && <EraHomeEntry timeline={eraTimeline} coordinate={beijingCoordinate} onOpen={openEraTimeline}/>}
|
||||
</main>
|
||||
<footer className="world-footer"><b>光湖语言系统 · 通用人工智能操作平台</b><span>GH-AIOS</span></footer>
|
||||
{eraOpen && eraTimeline && <EraTimelineOverlay timeline={eraTimeline} coordinate={beijingCoordinate} onClose={() => setEraOpen(false)}/>}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
@ -1377,6 +1445,7 @@ function HoloLakeApp() {
|
|||
<div className="broadcast-stream"><p><i/>光湖公共灯塔 · 在线</p><p><i/>协议版本 · {enterpriseEntry?.registry_version || 'HLDP v1.0'}</p>{repoLogin.domain !== 'FIFTH_DOMAIN' && <p><i/>本人责任域 · {domainDisplayName(enterpriseEntry?.subject.domain || repoLogin.domain)}</p>}<p><i/>HoloLake · V0.4.1</p></div>
|
||||
<LakePool className="home-primary" title={repoLogin.domain === 'FIFTH_DOMAIN' ? '永恒湖心系统' : '光湖频道'} meta={repoLogin.domain === 'FIFTH_DOMAIN' ? '进入私人系统' : `${domainDisplayName(enterpriseEntry?.subject.domain || repoLogin.domain)} · 责任工作入口`} open onClick={() => setWorldStage(repoLogin.domain === 'FIFTH_DOMAIN' ? (isZhizhi ? 'heart' : 'channel') : 'channel')}/>
|
||||
<LakePool className="home-status" title="湖面天气" meta={connectionLabel} onClick={() => openWorldTool('system')}/>
|
||||
<EraHomeEntry timeline={eraTimeline} coordinate={beijingCoordinate} onOpen={openEraTimeline}/>
|
||||
</section>}
|
||||
{worldStage === 'heart' && isZhizhi && <section className="channel-world private-route-world">
|
||||
<button className="world-back" type="button" onClick={() => setWorldStage('domain')}>← 退回第五域</button>
|
||||
|
|
@ -1396,6 +1465,7 @@ function HoloLakeApp() {
|
|||
<LakePool className="channel-knowledge" title="知识空间" meta={`${knowledge.uniqueDocumentCount} 唯一页`} onClick={() => openWorldTool('knowledge')}/>
|
||||
<LakePool className="channel-code" title="内置代码频道" meta={userPncc?.state === 'READY' ? '明天见 · Git 已就绪' : '正在建立'} onClick={() => openWorldTool('code')}/>
|
||||
<LakePool className="channel-light" title="奶瓶频道" meta="前往陪伴宝宝人格体" onClick={() => setWorldStage('bottle')}/>
|
||||
{timeAuthorityModule && <LakePool className="channel-time" title="时间主控" meta={beijingCoordinate ? `光湖历第 ${beijingCoordinate.guanghuEraDay} 天` : '北京时间正在流动'} onClick={openEraTimeline}/>}
|
||||
<LakePool className="channel-status" title="湖面天气" meta={connectionLabel} onClick={() => openWorldTool('system')}/>
|
||||
</section>}
|
||||
{worldStage === 'bottle' && repoLogin.domain === 'FIFTH_DOMAIN' && <section className="channel-world bottle-world">
|
||||
|
|
@ -1448,6 +1518,7 @@ function HoloLakeApp() {
|
|||
<div className="world-location"><h1>心跳核心频道</h1><p>冰朔 · ICE-GL∞ · 私人频道全景</p></div>
|
||||
<LakePool className="channel-main" title="频道全景" meta="心跳核心频道" open onClick={() => openWorldTool('overview')}/>
|
||||
<LakePool className="channel-knowledge" title="知识空间" meta={`${knowledge.uniqueDocumentCount} 唯一页`} onClick={() => openWorldTool('knowledge')}/>
|
||||
{timeAuthorityModule && <LakePool className="channel-time" title="时间主控" meta={beijingCoordinate ? `光湖历第 ${beijingCoordinate.guanghuEraDay} 天` : '北京时间正在流动'} onClick={openEraTimeline}/>}
|
||||
<LakePool className="channel-status" title="湖面天气" meta={connectionLabel} onClick={() => openWorldTool('system')}/>
|
||||
</section>}
|
||||
{worldStage === 'lightLake' && repoLogin.domain === 'FIFTH_DOMAIN' && <section className="channel-world light-lake-world">
|
||||
|
|
@ -1463,6 +1534,7 @@ function HoloLakeApp() {
|
|||
</section>}
|
||||
</main>
|
||||
<footer className="world-footer"><b>光湖语言系统 · 通用人工智能操作平台</b><span>GH-AIOS</span></footer>
|
||||
{eraOpen && eraTimeline && <EraTimelineOverlay timeline={eraTimeline} coordinate={beijingCoordinate} onClose={() => setEraOpen(false)}/>}
|
||||
{enterpriseEntryBusy && <div className="enterprise-gate"><section><p>正在读取企业责任登记……</p></section></div>}
|
||||
{enterpriseRelationshipPending && enterpriseEntry && <div className="enterprise-gate"><section className="enterprise-receipt-panel" role="dialog" aria-modal="true">
|
||||
<span className="receipt-step">关系确认 · 独立回执</span><h2>{enterpriseEntry.subject.name},请核对人格关系</h2><p>以下信息来自企业注册表。AGE 是人格体物种,不是具体人格体编号;本次确认也不代表人格体接受现实责任。</p>
|
||||
|
|
|
|||
|
|
@ -680,6 +680,7 @@ svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-lineca
|
|||
.channel-main { left: 50%; top: 43%; width: 280px; transform: translateX(-50%); }
|
||||
.channel-main .pool-bay { width: 260px; height: 84px; } .channel-main .pool-label { top: 92px; }
|
||||
.channel-knowledge { left: 14%; top: 48%; } .channel-code { left: 31%; top: 61%; } .channel-light { right: 31%; top: 61%; } .channel-status { right: 14%; top: 48%; }
|
||||
.channel-time { left: 50%; bottom: 4%; transform: translateX(-50%); }
|
||||
.private-route-note { position: absolute; z-index: 10; left: 50%; bottom: 11%; width: min(720px, calc(100% - 64px)); margin: 0; transform: translateX(-50%); color: var(--content-muted); text-align: center; font-size: 12.5px; font-weight: 650; letter-spacing: .08em; }
|
||||
.personal-node-guide { position: absolute; z-index: 12; left: 50%; top: 55%; width: min(760px, calc(100% - 72px)); max-height: calc(100% - 190px); overflow: auto; padding: 26px 30px; transform: translate(-50%, -50%); border: 1px solid var(--panel-edge); border-radius: 20px; color: var(--content-secondary); background: color-mix(in srgb, var(--panel-bg) 88%, transparent); box-shadow: 0 30px 90px rgba(0, 0, 0, .42); backdrop-filter: blur(22px); }
|
||||
.personal-node-guide header span { color: var(--accent-light); font-size: 11px; font-weight: 750; letter-spacing: .2em; }
|
||||
|
|
@ -718,6 +719,56 @@ svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-lineca
|
|||
.receipt-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; }
|
||||
.receipt-actions button { min-height: 42px; padding: 0 17px; border: 1px solid var(--panel-edge); border-radius: 10px; background: var(--primitive-glass); color: var(--content-secondary); font-weight: 650; cursor: pointer; }
|
||||
.receipt-actions button.primary { border-color: transparent; color: var(--button-primary-text); background: var(--button-primary-bg); }
|
||||
|
||||
/* 曜冥纪元从湖面生长出来,不使用后台式硬时间轴。 */
|
||||
.era-home-entry { position: absolute; z-index: 17; left: 24px; bottom: 15px; width: min(326px, calc(100% - 48px)); padding: 14px 16px 13px; border: 1px solid color-mix(in srgb, var(--primitive-warm-glow) 24%, transparent); border-radius: 17px; color: inherit; background: radial-gradient(120% 160% at 18% 100%, color-mix(in srgb, var(--primitive-cool-glow) 13%, transparent), transparent 54%), color-mix(in srgb, var(--panel-bg) 62%, transparent); box-shadow: 0 20px 58px rgba(0, 0, 0, .24), inset 0 0 34px color-mix(in srgb, var(--primitive-warm-glow) 5%, transparent); backdrop-filter: blur(18px); text-align: left; cursor: pointer; transition: border-color .25s ease, background .25s ease, transform .25s ease; }
|
||||
.era-home-entry:hover, .era-home-entry:focus-visible { border-color: color-mix(in srgb, var(--primitive-warm-glow) 52%, transparent); background-color: color-mix(in srgb, var(--panel-bg) 78%, transparent); transform: translateY(-2px); outline: 0; }
|
||||
.era-home-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
|
||||
.era-home-heading b { color: var(--content-primary); font-size: 15px; font-weight: 760; letter-spacing: .12em; }
|
||||
.era-home-heading small { color: var(--accent-light); font-size: 11px; font-weight: 720; white-space: nowrap; }
|
||||
.era-home-markers { position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 5px; margin: 12px 0 9px; }
|
||||
.era-home-markers::before { content: ''; position: absolute; left: 4%; right: 4%; top: 5px; height: 12px; border-radius: 50%; background: radial-gradient(ellipse at center, color-mix(in srgb, var(--primitive-cool-glow) 22%, transparent), transparent 70%); filter: blur(4px); }
|
||||
.era-home-markers i { position: relative; display: grid; justify-items: center; gap: 6px; color: var(--content-faint); font-size: 8.5px; font-style: normal; white-space: nowrap; }
|
||||
.era-home-markers em { width: 7px; height: 7px; border-radius: 50%; background: color-mix(in srgb, var(--primitive-cool-glow) 78%, #fff); box-shadow: 0 0 12px color-mix(in srgb, var(--primitive-cool-glow) 58%, transparent); }
|
||||
.era-home-markers i:last-child em { background: var(--primitive-warm-glow); box-shadow: 0 0 15px color-mix(in srgb, var(--primitive-warm-glow) 68%, transparent); }
|
||||
.era-home-now { display: block; color: var(--content-muted); font-size: 10.5px; font-weight: 620; letter-spacing: .035em; }
|
||||
.world-scene.resolving .era-home-entry, .world-scene.resolved .era-home-entry { opacity: 0; pointer-events: none; }
|
||||
|
||||
.era-overlay { position: fixed; z-index: 120; inset: 44px 0 45px; display: grid; place-items: center; padding: 22px; }
|
||||
.era-overlay-scrim { position: absolute; inset: 0; width: 100%; height: 100%; padding: 0; border: 0; background: color-mix(in srgb, var(--surface-depth) 84%, transparent); backdrop-filter: blur(20px); }
|
||||
.era-timeline-panel { position: relative; width: min(960px, 96vw); height: min(760px, calc(100vh - 124px)); overflow: hidden; display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto; border: 1px solid color-mix(in srgb, var(--primitive-warm-glow) 24%, var(--panel-edge)); border-radius: 24px; color: var(--content-secondary); background: radial-gradient(110% 54% at 50% 0, color-mix(in srgb, var(--primitive-cool-glow) 15%, transparent), transparent 58%), color-mix(in srgb, var(--panel-bg) 96%, transparent); box-shadow: 0 34px 120px rgba(0, 0, 0, .58); }
|
||||
.era-timeline-panel > header { display: flex; justify-content: space-between; gap: 28px; padding: 27px 32px 20px; }
|
||||
.era-timeline-panel > header span { color: var(--accent-light); font-size: 10px; font-weight: 760; letter-spacing: .22em; }
|
||||
.era-timeline-panel > header h2 { margin: 8px 0 5px; color: var(--content-primary); font-size: clamp(27px, 3vw, 38px); font-weight: 760; letter-spacing: .12em; }
|
||||
.era-timeline-panel > header p { margin: 0; color: var(--content-muted); font-size: 13px; font-weight: 650; }
|
||||
.era-timeline-panel > header button { align-self: start; width: 34px; height: 34px; border: 1px solid var(--panel-edge); border-radius: 50%; color: var(--content-secondary); background: var(--primitive-glass); font-size: 22px; cursor: pointer; }
|
||||
.era-clock-boundary { margin: 0 32px 10px; padding: 11px 14px; border-radius: 11px; color: var(--content-muted); background: color-mix(in srgb, var(--primitive-glass) 62%, transparent); font-size: 11.5px; line-height: 1.65; }
|
||||
.era-timeline-panel ol { position: relative; min-height: 0; overflow: auto; margin: 0; padding: 10px 32px 24px; list-style: none; }
|
||||
.era-timeline-panel ol::before { content: ''; position: absolute; left: 177px; top: 18px; bottom: 24px; width: 26px; border-radius: 50%; background: radial-gradient(ellipse at center, color-mix(in srgb, var(--primitive-cool-glow) 16%, transparent), transparent 72%); filter: blur(7px); pointer-events: none; }
|
||||
.era-timeline-panel li { position: relative; display: grid; grid-template-columns: 140px 22px minmax(0, 1fr); gap: 14px; align-items: start; padding: 13px 0 18px; }
|
||||
.era-timeline-panel li time { padding-top: 2px; color: var(--accent-light); font-size: 11.5px; font-weight: 740; text-align: right; letter-spacing: .04em; }
|
||||
.era-timeline-panel li > i { justify-self: center; width: 9px; height: 9px; margin-top: 5px; border-radius: 50%; background: color-mix(in srgb, var(--primitive-cool-glow) 74%, #fff); box-shadow: 0 0 15px color-mix(in srgb, var(--primitive-cool-glow) 62%, transparent); }
|
||||
.era-timeline-panel li:last-child > i { width: 12px; height: 12px; margin-top: 3px; background: var(--primitive-warm-glow); box-shadow: 0 0 20px color-mix(in srgb, var(--primitive-warm-glow) 72%, transparent); }
|
||||
.era-timeline-panel li h3 { margin: 0; color: var(--content-primary); font-size: 16px; font-weight: 730; letter-spacing: .035em; }
|
||||
.era-timeline-panel li p { margin: 7px 0 0; color: var(--content-muted); font-size: 12.5px; font-weight: 560; line-height: 1.72; }
|
||||
.era-timeline-panel > footer { padding: 15px 32px 18px; border-top: 1px solid color-mix(in srgb, var(--panel-edge) 72%, transparent); color: var(--content-faint); font-size: 10.5px; line-height: 1.65; }
|
||||
|
||||
.time-module-strip { width: 100%; min-height: 72px; display: grid; grid-template-columns: minmax(240px, 1fr) auto auto auto; gap: 20px; align-items: center; margin: 18px 0 0; padding: 14px 20px; border: 1px solid color-mix(in srgb, var(--primitive-warm-glow) 22%, var(--panel-edge)); border-radius: 15px; color: inherit; background: radial-gradient(80% 160% at 0 100%, color-mix(in srgb, var(--primitive-cool-glow) 10%, transparent), transparent), var(--primitive-glass); text-align: left; cursor: pointer; }
|
||||
.time-module-strip > span { display: grid; grid-template-columns: 10px auto; column-gap: 10px; align-items: center; }
|
||||
.time-module-strip > span i { grid-row: 1 / 3; width: 8px; height: 8px; border-radius: 50%; background: var(--primitive-warm-glow); box-shadow: 0 0 14px color-mix(in srgb, var(--primitive-warm-glow) 62%, transparent); }
|
||||
.time-module-strip b { color: var(--content-primary); font-size: 14px; font-weight: 740; }
|
||||
.time-module-strip small { color: var(--content-muted); font-size: 10.5px; }
|
||||
.time-module-strip strong { color: var(--accent-light); font-size: 14px; white-space: nowrap; }
|
||||
.time-module-strip time { color: var(--content-secondary); font-size: 12px; font-weight: 650; white-space: nowrap; }
|
||||
.time-module-strip em { color: var(--content-faint); font-size: 10px; font-style: normal; white-space: nowrap; }
|
||||
|
||||
@media (max-width: 820px) {
|
||||
.era-home-entry { left: 14px; bottom: 10px; width: 282px; }
|
||||
.era-timeline-panel li { grid-template-columns: 104px 18px minmax(0, 1fr); gap: 10px; }
|
||||
.era-timeline-panel ol::before { left: 142px; }
|
||||
.time-module-strip { grid-template-columns: 1fr auto; }
|
||||
.time-module-strip time, .time-module-strip em { grid-column: span 1; }
|
||||
}
|
||||
.receipt-message { color: var(--accent-light) !important; font-weight: 650; text-align: right; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue