// Fossyl primitives — shared building blocks const { useState, useEffect, useMemo, useRef, createContext, useContext } = React; // ---------- Logo / wordmark ---------- function Logo({ size = 22, withText = true, ink }) { const color = ink || 'var(--ink)'; return (
F {withText && Fossyl}
); } // ---------- Fossil iconographic placeholder ---------- function FossilPlaceholder({ w = 260, h = 180, label = "STRATIGRAPHIC MAP", sub = "placeholder" }) { return (
{label}
{sub}
); } // ---------- Measurement rule ---------- function Rule({ label, value, align = 'left' }) { return (
{label && {label}}
{value}
); } // ---------- Corner-marked frame ---------- function Framed({ children, style, ...rest }) { return (
{children}
); } // ---------- Section header with eyebrow ---------- function SectionHeader({ number, eyebrow, title, kicker, right }) { return (
{number && § {number}} {eyebrow && {eyebrow}}

{title}

{kicker &&

{kicker}

}
{right &&
{right}
}
); } // ---------- Stat block ---------- function Stat({ label, value, unit, tone }) { const toneClass = tone ? tone : ''; return (
{label}
{value} {unit && {unit}}
); } // ---------- Risk bar ---------- function RiskBar({ value, max = 100 }) { const pct = Math.min(100, (value / max) * 100); const tone = value > 70 ? 'var(--rust)' : value > 40 ? 'var(--bone)' : 'var(--lichen)'; return (
{value}
); } // ---------- Ticks (measurement) ---------- function Ticks({ count = 40, height = 10 }) { return ( {[...Array(count)].map((_, i) => ( ))} ); } // ---------- Field-note margin mark ---------- function FieldNote({ index, children }) { return (
{index != null && F-{String(index).padStart(4, '0')}}
{children}
); } // ---------- Nav context (sidebar/top-nav/doc) ---------- const NavContext = createContext({ current: 'landing', go: () => {} }); function useNav() { return useContext(NavContext); } // ---------- Auth context ---------- const AuthContext = createContext({ authed: false, paid: false, hasRun: false, signIn: () => {}, signUp: () => {}, signOut: () => {}, setPaid: () => {}, setHasRun: () => {}, plan: null, setPlan: () => {}, }); function useAuth() { return useContext(AuthContext); } // ---------- Toast ---------- const ToastContext = createContext({ toast: () => {} }); function useToast() { return useContext(ToastContext); } function ToastProvider({ children }) { const [items, setItems] = useState([]); const toast = (msg, opts = {}) => { const id = Math.random().toString(36).slice(2); window.__fossylToast = toast; // register globally for out-of-component callers const tone = opts.tone || 'default'; setItems((xs) => [...xs, { id, msg, tone }]); setTimeout(() => setItems((xs) => xs.filter((x) => x.id !== id)), opts.duration || 2500); }; return ( {children}
{items.map((t) => (
{t.msg}
))}
); } // ---------- Workspace join modal (shown to invited users on login) ---------- function WorkspaceJoinModal({ invite, onAccept, onDecline, accepting }) { const { workspace_name, invited_by, role } = invite; const roleDesc = { Viewer: 'can browse existing excavation reports but cannot start new scans.', Member: 'can run new excavations and access all reports.', Admin: 'can run excavations, view reports, and manage workspace members.', }[role] || ''; return (
Workspace invitation
You've been invited to join {workspace_name}.

{invited_by} added you as a{' '} {role}.{roleDesc ? ` ${role}s ${roleDesc}` : ''}

Accepting moves you into {workspace_name}'s workspace and grants you access to their active plan.
); } // ---------- Terms modal ---------- function TermsModal({ onAccept, onDecline }) { return (
{ if (e.target === e.currentTarget) onDecline(); }} >
Fossyl — Terms of service & data handling rev. 2026-05
§ 1 · Service

Fossyl ("the Service") analyses Plone and Zope codebases from files you upload (repository ZIP, ZODB export, optional SQL schema). The Service is operated by Fossyl UG (haftungsbeschränkt, in formation), Erich-Kirsten-Straße 12, 10405 Berlin, Germany. By creating an account or initiating an excavation you accept these terms.

§ 2 · Uploaded files & ephemeral processing

Files you upload are stored temporarily in AWS S3 (EU Frankfurt). They are deleted automatically within 24 hours and immediately after your report is generated. Fossyl does not retain, copy, or analyse uploaded source code beyond what is necessary to produce the requested report. Generated HTML reports are retained according to your plan's retention window (30 days / 90 days / 1 year / unlimited).

§ 3 · AI explanations (§6 of your report)

If you enable "AI plain-English explanations", Fossyl sends artifact signatures only — never full source code — to the Anthropic API. A signature contains the artifact name, type, detected coupling score, and a short structural fingerprint. No business logic, no credentials, and no comments are included. Anthropic's data usage policy applies to these requests.

§ 4 · Acceptable use

You may not upload files that contain malware, files you are not authorised to analyse, or files whose analysis would violate applicable law. Automated abuse (scripted bulk uploads beyond your plan's scan quota) is prohibited. Fossyl reserves the right to suspend accounts that violate these terms without refund.

§ 5 · Billing & refunds

Subscriptions are billed monthly or annually via Stripe. Cancellation takes effect at the end of the current billing period; no prorated refunds are issued for unused time except where required by applicable law. The one-off Specimen plan carries a 14-day refund guarantee if the generated report is empty or corrupt — contact eri@getfossyl.dev.

§ 6 · Liability

The Service is provided "as is". Reports are informational and do not constitute legal, security, or architectural advice. Fossyl's liability for damages is limited to the amount paid in the 12 months preceding the claim, to the extent permitted by German law.

§ 7 · Data handling addendum (GDPR)

Fossyl processes personal data as follows:

  • Account data — email address, name, organisation — stored in AWS Cognito and DynamoDB (EU Frankfurt). Retained until account deletion.
  • Usage data — scan job metadata (file sizes, scan duration, artifact counts) — stored in DynamoDB (EU Frankfurt). Retained per plan.
  • Payment data — handled exclusively by Stripe; Fossyl does not store card numbers or bank details.
  • Sub-processors — AWS EMEA SARL (Frankfurt), Stripe Payments Europe Ltd (Dublin), Anthropic PBC (San Francisco, Standard Contractual Clauses apply).

You have the right to access, rectify, and erase your personal data. Requests: eri@getfossyl.dev. Supervisory authority: Berliner Beauftragte für Datenschutz und Informationsfreiheit.

); } function TransferOwnershipModal({ transfer, onAccept, onDecline, accepting }) { return (
Ownership transfer

{transfer.from_name} wants to hand you their workspace.

Workspace: {transfer.workspace_name}

If you accept, you become the Owner and {transfer.from_name} becomes a Member. If you decline, nothing changes.

); } Object.assign(window, { Logo, FossilPlaceholder, Rule, Framed, SectionHeader, Stat, RiskBar, Ticks, FieldNote, NavContext, useNav, AuthContext, useAuth, ToastContext, useToast, ToastProvider, TermsModal, WorkspaceJoinModal, TransferOwnershipModal, });