imitation
← all crawls

PairDrop | Transfer Files Cross-Platform. No Setup, No Signup.

https://pairdrop.net/

Instantly share images, videos, PDFs, and links with people nearby. Peer2Peer and Open Source. No Setup, No Signup.

pairdrop.net screenshot

Visuals

Colors

Primary
#4285f4
Background
#f2f2f2
Surface
#ffffff
Text Primary
#4285f4
Text Secondary
#333333

Typography

Aa
Display
Open Sans
45px / w400
Aa
Heading
Open Sans
22px / w400
Aa
Body
Open Sans
14px / w400
Aa
Label
Open Sans
14px / w400

Spacing

Xs
3px
Sm
4px
Md
5px
Lg
8px
Xl
10px

Radius

Sm
6px
Md
12px
Lg
20px
Pill
9999px

Shadows

Sm
Md
Lg

Mode

Light mode
Background
Sample text on canvas
Bg#f2f2f2
Text#4285f4
Muted#333333

Motion

Levelsubtle
Duration300ms
Easingease-in-out

Stack

Frameworkvanilla
Iconscustom

Full Palette · 20 tokens

Brand
primary
#4285f4
primary-active
#2957c9
primary-hover
#3367d6
Surface
canvas
#f2f2f2
surface
#ffffff
surface-muted
#757575
surface-overlay
rgba(128, 128, 128, 0.5)
surface-soft
#ffffff
Text
body
#333333
ink
#4285f4
muted
#5b5b66
on-dark
#ffffff
on-primary
#ffffff
Hairlines & Borders
border-input
#cccccc
hairline
#e0e0e0
Semantic
error
#d93025
link
#4285f4
link-active
#3367d6
success
#00a69c
warning
#ed9d01

Typography Roles · 9

body-md
Aa
14px / w400
body-sm
Aa
13px / w400
button-label
Aa
12px / w700
caption
Aa
12px / w400
display-lg
Aa
32px / w400
display-xl
Aa
45px / w400
input-lg
Aa
30px / w400
label-md
Aa
14px / w400
title-md
Aa
22px / w400

Components · 26

device-name-display
backgroundColortransparent
padding{spacing.base} {spacing.md}
textColor{colors.body}
typography{typography.label-md}
device-name-value
backgroundColor{colors.surface-muted}
padding2px {spacing.sm}
rounded{rounded.sm}
textColor{colors.on-primary}
typography{typography.label-md}
dialog-backdrop
backgroundColor{colors.surface-overlay}
textColor{colors.body}
dialog-form
backgroundColortransparent
textColor{colors.body}
typography{typography.body-md}
dialog-paper
backgroundColor{colors.surface}
maxWidth480px
padding{spacing.xxl}
rounded{rounded.lg}
textColor{colors.body}
typography{typography.body-md}
discovery-status-badge
backgroundColor{colors.primary}
padding3px {spacing.lg}
rounded{rounded.pill}
textColor{colors.on-primary}
typography{typography.button-label}
discovery-status-label
backgroundColortransparent
textColor{colors.muted}
typography{typography.caption}
discovery-wrapper
backgroundColor{colors.surface}
padding{spacing.base} {spacing.lg}
rounded{rounded.xl}
textColor{colors.body}
typography{typography.body-md}
edit-icon
backgroundColortransparent
size16px
textColor{colors.body}
footer-panel
backgroundColortransparent
padding{spacing.xl} 0
textColor{colors.body}
typography{typography.body-md}
hero-band
backgroundColor{colors.canvas}
padding{spacing.wide} {spacing.section}
textColor{colors.body}
typography{typography.display-xl}
hero-headline
backgroundColortransparent
padding{spacing.lg} 0
textColor{colors.ink}
typography{typography.title-md}
hero-subheadline
backgroundColortransparent
padding{spacing.base} 0 {spacing.xl}
textColor{colors.body}
typography{typography.body-md}
icon-radar
backgroundColortransparent
size64px
textColor{colors.ink}
input-code
backgroundColor{colors.canvas}
height56px
padding{spacing.lg}
rounded{rounded.md}
textColor{colors.body}
typography{typography.input-lg}
input-code-focus
backgroundColor{colors.surface}
rounded{rounded.md}
textColor{colors.body}
typography{typography.input-lg}
language-option
backgroundColortransparent
padding{spacing.base}
textColor{colors.primary}
typography{typography.button-label}
nav-icon-button
backgroundColortransparent
padding8px
size40px
textColor{colors.body}
nav-icon-button-selected
backgroundColor{colors.body}
rounded{rounded.pill}
size24px
textColor{colors.canvas}
panel-card
backgroundColor{colors.surface}
padding{spacing.lg}
rounded{rounded.lg}
textColor{colors.body}
typography{typography.body-md}
panel-card-border
backgroundColor{colors.surface}
padding{spacing.base} {spacing.lg}
rounded{rounded.xl}
textColor{colors.body}
typography{typography.body-md}
radar-container
backgroundColortransparent
padding{spacing.wide}
textColor{colors.ink}
text-button
backgroundColortransparent
padding{spacing.base}
textColor{colors.primary}
typography{typography.button-label}
text-button-uppercase
backgroundColortransparent
padding{spacing.base}
textColor{colors.primary}
typography{typography.button-label}
top-nav
backgroundColortransparent
height48px
padding8px 12px
textColor{colors.body}
typography{typography.body-md}
traffic-notice
backgroundColortransparent
padding{spacing.lg}
textColor{colors.muted}
typography{typography.caption}

design.md

PairDrop Design System

Overview

PairDrop presents itself as a serene, utilitarian file-transfer environment—a digital clearinghouse where the interface recedes so the action of sharing remains foreground. The design philosophy is one of radical minimalism: a cool gray {colors.canvas} background establishes a neutral field upon which brand-blue accents ({colors.primary} at #4285f4) punctuate only what demands attention—headlines, active states, and the signature radar icon that pulses at the center of the empty state.

The typographic voice is distinctly Open Sans, deployed at consistently light weights (never exceeding 400 for body copy, 700 only for micro-labels). The most distinctive typographic move is the expansive letter-spacing on display text ({typography.display-xl} carries 18px tracking), which lends the interface a technical, almost aerospace instrumentation quality. This is not a warm, conversational product—it's a precision tool.

Shape language favors generous rounding: {rounded.xl} at 20px for panels, {rounded.pill} for status badges, creating soft containment without playfulness. The concentric-circle radar motif—rendered in faint {colors.hairline} strokes—becomes the visual anchor when no devices are present, transforming emptiness into a state of anticipatory readiness.

Sub-systems observed include: the header utility cluster (icon-only actions), the discovery dialect (device naming + network status), and a modal/dialog system for room codes and settings.

Key Characteristics:

  • Cool gray canvas ({colors.canvas} — #f2f2f2) with white elevated surfaces ({colors.surface})
  • Single brand color ({colors.primary} — #4285f4) applied to headlines, links, badges, and interactive states
  • Open Sans throughout, with extreme letter-spacing (18px) on display text creating instrument-panel aesthetics
  • Rounded containers ({rounded.xl} — 20px, {rounded.pill} for badges) softening the technical voice
  • Signature radar visualization using concentric {colors.hairline} circles as empty-state branding
  • Pill-shaped status indicators ({component.discovery-status-badge}) for network discovery state
  • Material-style elevation via layered shadows ({extensions.shadows.md})
  • Uppercase micro-labels ({typography.button-label} — 12px/700) for secondary actions
  • Transparent backgrounds on navigation, allowing the canvas to show through

Colors

Brand & Accent

  • Primary ({colors.primary} — #4285f4): The singular brand blue—used for headlines, links, icon fills in active/radar states, badge backgrounds, and all primary interactive elements. This is Google Blue, carrying associations of connectivity and trust.
  • Primary Hover ({colors.primary-hover} — #3367d6): Darkened blue for hover states on links and buttons.
  • Primary Active ({colors.primary-active} — #2957c9): Further darkened for pressed/active states.

Surface

  • Canvas ({colors.canvas} — #f2f2f2): The foundational page background—a cool, light gray that reduces eye strain during extended use and provides subtle differentiation from pure white surfaces.
  • Surface ({colors.surface} — #ffffff): Pure white used for elevated panels, cards, dialogs, and input fields—creates clear layer separation from the canvas.
  • Surface Soft ({colors.surface-soft} — #ffffff): Alias for surface in this system; both resolve to white.
  • Surface Muted ({colors.surface-muted} — #757575): Medium-gray used for disabled-looking inline backgrounds like the device name highlight.
  • Surface Overlay ({colors.surface-overlay} — rgba(128, 128, 128, 0.5)): Semi-transparent dark overlay for modal backdrops.

Text

  • Ink ({colors.ink} — #4285f4): The headline color—intentionally set to brand blue rather than black, making primary messaging carry brand voltage.
  • Body ({colors.body} — #333333): Near-black for body text, labels, and UI chrome—provides maximum readability against light surfaces.
  • Muted ({colors.muted} — #5b5b66): Mid-gray for secondary text, instructions, notices, and de-emphasized content.
  • On Primary ({colors.on-primary} — #ffffff): White text for rendering atop blue backgrounds (badges, buttons).
  • On Dark ({colors.on-dark} — #ffffff): White text reserved for any future dark-mode surfaces or dark backgrounds.

Hairlines & Borders

  • Hairline ({colors.hairline} — #e0e0e0): Light gray for the concentric radar circles, subtle dividers, and decorative lines.
  • Border Input ({colors.border-input} — #cccccc): Slightly darker gray for input field borders when visible.

Semantic

  • Success ({colors.success} — #00a69c): Teal/green for successful transfer states or confirmation indicators.
  • Warning ({colors.warning} — #ed9d01): Amber/orange for cautionary states (transfer interruptions, network issues).
  • Error ({colors.error} — #d93025): Red for failure states, connection errors, or destructive actions.
  • Link ({colors.link} — #4285f4): Matches primary—clickable text and icon buttons use brand blue.
  • Link Active ({colors.link-active} — #3367d6): Darkened blue for visited or active link states.

Typography

Font Family

The system relies exclusively on Open Sans, a humanist sans-serif designed by Steve Matteson. The fallback stack (-apple-system, BlinkMacSystemFont, sans-serif) ensures native font rendering on Apple devices (San Francisco), ChromeOS (BlinkMacSystemFont), and generic sans-serif elsewhere. Open Sans was chosen for its excellent legibility at small sizes, neutral personality (it doesn't compete with content), and strong performance across Latin, Cyrillic, and Arabic scripts—all relevant given PairDrop's multilingual support.

There is no distinct heading font; hierarchy is achieved through scale, weight modulation (400 vs. 700), color shifts (blue headlines vs. gray body), and the dramatic letter-spacing on display text.

Hierarchy

| Token | Size | Weight | Line Height | Letter Spacing | Use | |---|---|---|---|---|---| | {typography.display-xl} | 45px | 400 | 40px | 18px | Room codes, large numeric displays | | {typography.display-lg} | 32px | 400 | 38px | 12px | Hero-scale messaging (inferred) | | {typography.title-md} | 22px | 400 | 32px | -0.264px | Primary headline ("Open PairDrop...") | | {typography.body-md} | 14px | 400 | 20px | normal | Standard body text, labels, descriptions | | {typography.body-sm} | 13px | 400 | 18px | normal | Secondary body text (inferred) | | {typography.label-md} | 14px | 400 | 20px | normal | Inline labels ("You are known as:") | | {typography.button-label} | 12px | 700 | 16px | 0.05em | Language options, micro-buttons, uppercase labels | | {typography.input-lg} | 30px | 400 | 36px | normal | Room code input fields | | {typography.caption} | 12px | 400 | 16px | normal | Traffic notice, fine print |

Principles

The typography system trusts size and color over weight to establish hierarchy. Notice that the primary headline ({typography.title-md} at 22px) uses the same 400 weight as body text—it stands out because it's rendered in {colors.ink} (brand blue) while body text is {colors.body} (near-black). This is an unusual and deliberate choice: the blue headline signals "this is the brand speaking" while the darker body text carries the informational payload.

The letter-spacing convention is the system's most expressive typographic feature. At {typography.display-xl}, the 18px tracking creates an almost monospaced, instrumentation-readout effect—appropriate for a tool dealing with device pairing and network codes. This expands to fill horizontal space and slows reading speed, encouraging careful attention (exactly what you want when sharing a room code). By contrast, {typography.title-md} uses slightly negative tracking (-0.264px) for tighter, more conventional headline setting.

Weight modulation is reserved exclusively for micro-elements: {typography.button-label} at 700 weight and uppercase transform creates a distinct "control label" dialect for language selectors and tertiary actions. Body text never exceeds 400 weight, maintaining the calm, unshouty voice.

Note on Font Substitutes

Open Sans is available via Google Fonts (https://fonts.google.com/specimen/Open+Sans) under the Apache License 2.0. For self-hosting (as PairDrop does, serving .ttf from /fonts/OpenSans/static/OpenSans-Medium.ttf), download the full family including Light (300), Regular (400), Semi-Bold (600), and Bold (700) weights. If Open Sans cannot be loaded, the -apple-system fallback provides San Francisco on Apple devices—an acceptable substitute with similar humanist proportions. For environments requiring system fonts only, Noto Sans (Google Fonts) offers the closest metric compatibility to Open Sans, particularly for the Cyrillic and Arabic ranges PairDrop supports.

Layout

Spacing System

  • Base unit: Derived from the dominant {spacing.base} value of 7px—an unconventional base (not 4px or 8px), suggesting the original design used a 7px grid or derived spacing from icon metrics.

  • Tokens:

    • {spacing.xxs} (2px): Tight internal padding, micro-adjustments
    • {spacing.xs} (3px): Badge internal padding, tiny gaps
    • {spacing.sm} (4px): Icon-text gaps, compact spacing
    • {spacing.md} (5px): Small element gaps
    • {spacing.base} (7px): Button padding baseline, common vertical rhythm
    • {spacing.lg} (8px): Standard gap between related elements
    • {spacing.xl} (10px): Comfortable touch target padding
    • {spacing.xxl} (14px): Relaxed padding for larger containers
    • {spacing.section} (16px): Section-level padding, header horizontal padding
    • {spacing.wide} (24px): Major section breaks, hero vertical spacing
    • {spacing.container} (490px): Fixed width for central content column (observed on <section>)
  • Section padding (vertical): {spacing.wide} (24px) — used between the hero message block and the footer panel.

  • Card internal padding: {component.panel-card} uses {spacing.lg} (8px); {component.dialog-paper} uses {spacing.xxl} (14px); {component.discovery-wrapper} uses {spacing.base} {spacing.lg} (7px vertical, 8px horizontal).

  • Gutters: Header uses {spacing.section} (16px) horizontal padding. The central content column appears constrained to approximately {spacing.container} (490px) width on smaller views, expanding on wider viewports.

Grid & Container

  • Max content width: The header spans 1440px max-width (from extracted container data). The central instruction section constrains to 314px in its observed state, but this likely responds to viewport width.
  • Density choice: Editorial-sparse density—the interface shows one primary message, one instructional subtext, one radar visualization, and one footer panel. This is not a dashboard; it's a landing-state interface.
  • Grid behavior: No multi-column grid observed in the screenshot. The layout is fundamentally a single centered column with absolutely-positioned header utilities (top-right) and footer content (bottom-center).
  • Hero column split: Not applicable—hero content is center-aligned in a single column.

Whitespace Philosophy

PairDrop employs generous negative space as a design feature. The {colors.canvas} background dominates approximately 80% of the viewport, with content clustered in the center third. This emptiness is intentional: it creates focus on the single call-to-action ("open PairDrop on other devices") and makes the radar visualization feel like it's broadcasting into open space. The whitespace is not passive filler—it's the "air" in which device discovery happens.

Header Architecture

+----------------------------------------------------------------------------------+
|                                                                    [🎥] [🔗] [🔔] [◐] [Aa] [?] |
+----------------------------------------------------------------------------------
|                                    (max-width: 1440px)                          |
|                         padding: 8px 12px                                        |
|                         justify-content: flex-end                                |
+----------------------------------------------------------------------------------+

The header uses row-reverse layout with wrap, positioning all icon buttons flush-right. Each icon button is a square {component.nav-icon-button} at 40px with transparent background. The theme toggle (sun/moon icon) shows a selected state as a filled pill.

Hero Section

+----------------------------------------------------------------------------------+
|                                                                                  |
|                              (concentric circles - radar)                        |
|                                          ◎                                       |
|                                                                                  |
|                    "Open PairDrop on other devices to send files"               |
|                         ({typography.title-md} - {colors.ink})                  |
|                                                                                  |
|              "Pair devices or enter a public room to be discoverable..."        |
|                           ({typography.body-md} - {colors.body})                |
|                                                                                  |
+----------------------------------------------------------------------------------+
|                                                                                  |
|            [radar icon: {component.icon-radar}]                                   |
|                                                                                  |
|         You are known as: [Azure Whitefish] ✏️                                   |
|                                                                              |
|         You can be discovered: [on this network]                                 |
|                                    ({component.discovery-status-badge})          |
|                                                                                  |
+----------------------------------------------------------------------------------+

Footer Panel

+------------------------------------------+
|                                          |
|              [radar logo SVG]             |
|                                          |
|   You are known as: [Azure Whitefish] ✏️  |
|   ({component.device-name-display})       |
|                                          |
|   +----------------------------------+   |
|   | You can be discovered: [on this  |   |
|   | network]                         |   |
|   | ({component.discovery-wrapper})  |   |
|   +----------------------------------+   |
|                                          |
+------------------------------------------+

Elevation & Depth

| Level | Treatment | Use | |---|---|---| | 0 (Flat) | No shadow, {colors.canvas} background | Page base, header background | | 1 (Raised) | {extensions.shadows.sm} | Subtle lift for cards (inferred) | | 2 (Floating) | {extensions.shadows.md} | Dialog papers, elevated panels | | 3 (Modal) | {extensions.shadows.lg} | Modal overlays, dropdowns (inferred) | | Focus ring | Outline or glow (not extracted) | Input focus, keyboard navigation |

The depth system follows a Material Design-inspired layered model, though executed with restraint. The primary elevation signal is the {extensions.shadows.md} shadow—a triple-layered shadow with different blur radii and opacities (14%, 12%, 40% at varying offsets) that creates a realistic floating effect for {component.dialog-paper} and potentially for {component.panel-card} when elevated.

Color-block elevation is equally important: {colors.surface} (white) panels sitting on {colors.canvas} (gray #f2f2f2) create perceived depth through value contrast alone, even before shadows are applied. This is the primary elevation mechanism for {component.discovery-wrapper} and {component.panel-card}.

Decorative Depth

The concentric radar circles constitute the signature decorative depth element. Rendered in {colors.hairline} (#e0e0e0) at increasing radii, these circles create a topographic/broadcast visualization that gives the empty state visual interest without adding literal content. The circles appear to be SVG or CSS-generated, positioned absolutely behind the central content. They fade in via the fade-in animation class observed in the DOM.

Shapes

Border Radius Scale

| Token | Value | Use | |---|---|---| | {rounded.sm} | 6px | Device name inline highlight, subtle rounding | | {rounded.DEFAULT} / {rounded.md} | 12px | Input fields ({component.input-code}), standard cards | | {rounded.lg} | 20px | Panel cards ({component.panel-card}), dialog papers | | {rounded.xl} | 30px | Discovery wrapper ({component.discovery-wrapper}), extra-rounded containers | | {rounded.pill} | 9999px | Status badges, theme toggle selected state | | {rounded.ellipse} | 20.8px / 30% | Elliptical radius (observed once—specialized use) |

The shape vocabulary progresses from gently rounded (6px) through comfortably rounded (12-20px) to fully pill-shaped (9999px). There are no sharp corners anywhere in the system—even the most utilitarian input field uses {rounded.md} (12px). The {rounded.pill} is reserved specifically for status indicators where the shape signals "badge/tag" rather than "container."

Photography Geometry

No photography is present in the PairDrop interface. Imagery consists entirely of:

  • SVG icons (radar, navigation icons, edit pencil)
  • CSS-generated concentric circles
  • Text-based device names

If user avatars were added (for identified peers), the {rounded.pill} or {rounded.lg} treatment would maintain consistency with existing rounded elements.

Components

No hover states documented. Hover behavior is unreliable to extract from a single screenshot. State variants live as separate entries in the components: frontmatter (e.g. {component.button-primary-active}, {component.text-input-focus}); add hover styling at implementation time per your stack's conventions.

Navigation

{component.top-nav} — The fixed header bar spanning the full viewport width at 48px height. Transparent background allows {colors.canvas} to show through. Contains icon buttons aligned to the right edge via row-reverse flex layout. Padding is {spacing.section} (16px) horizontally and {spacing.lg} (8px) vertically. No visible border-bottom; separation from content is purely spatial.

{component.nav-icon-button} — Square 40×40px touch targets containing SVG icons. Transparent background with {colors.body} text color. Zero border-radius in default state (sharp squares), which contrasts interestingly with the rounded elements below—suggesting these are "utility chrome" rather than content. Padding is {spacing.xl} (10px).

{component.nav-icon-button-selected} — The active/selected state for toggle buttons (observed on the theme toggle). Transforms to a 24px-wide pill shape with {rounded.pill}, filled with {colors.body} background and {colors.canvas} (white) foreground. This creates a clear "toggle on" indicator.

Hero & Messaging

{component.hero-band} — The full-width upper content area. Uses {colors.canvas} background (blending with page background). Contains the centered instructional message stack. Vertical padding of {spacing.wide} (24px) provides breathing room above the headline.

{component.hero-headline} — The primary message: "Open PairDrop on other devices to send files". Renders in {colors.ink} (brand blue #4285f4) at {typography.title-md} (22px/400). Center-aligned. Line height of 32px gives the two-line headline comfortable spacing. Negative letter-spacing (-0.264px) tightens the slightly large Open Sans characters for headline density.

{component.hero-subheadline} — Supporting instruction: "Pair devices or enter a public room...". Renders in {colors.body} (dark gray #333333) at {typography.body-md} (14px/400). Center-aligned beneath the headline. Provides the actionable context without competing visually.

{component.radar-container} — The area containing the concentric circle visualization and central radar icon. Transparent background. Padding of {spacing.wide} (24px). Houses the {component.icon-radar} at 64px, colored in {colors.ink} (blue). This component is purely decorative/branding—it transforms the empty-state from "nothing here" to "listening/broadcasting."

Footer & Identity

{component.footer-panel} — The bottom-center stacked panel containing device identity and discovery status. Column layout (flex-direction: column). Typography defaults to {typography.body-md}. Padding of {spacing.xxl} (14px) vertical.

{component.device-name-display} — The row showing "You are known as:" followed by the editable device name. Background transparent. Label text in {colors.body}, value rendered inside {component.device-name-value}.

{component.device-name-value} — The actual device name ("Azure Whitefish" in the screenshot). Background is {colors.surface-muted} (gray #757575)—this is notable as it's the only inline text-highlight using a non-white, non-brand background. Text is white ({colors.on-primary}). Rounded to {rounded.sm} (6px). Minimal padding (2px horizontal, 4px vertical). An edit icon (pencil) sits adjacent as {component.edit-icon}.

{component.discovery-wrapper} — The bordered container holding discovery status. White ({colors.surface}) background with visible border (inferred {colors.hairline}). Rounded to {rounded.xl} (30px)—the second-most rounded element after pills. Padding is asymmetric: {spacing.base} (7px) vertical, {spacing.lg} (8px) horizontal. This wraps the {component.discovery-status-label} and {component.discovery-status-badge} in a row layout.

{component.discovery-status-label} — "You can be discovered:" text in {colors.muted} gray at caption size. Precedes the badge.

{component.discovery-status-badge} — The "on this network" pill badge. Background is {colors.primary} (blue #4285f4), text is {colors.on-primary} (white). Typography is {typography.button-label} (12px/700). Rounded to {rounded.pill} (fully circular ends). Padding is 3px vertical, {spacing.lg} (8px) horizontal—creating a compact tag shape. This is the primary CTA-colored element in the footer.

Inputs & Forms

{component.text-button} — A text-only button with no visible background or border. Text color is {colors.primary} (blue). Typography at {typography.button-label} size (12px). Padding {spacing.base} (7px). Used for language selector options and tertiary actions.

{component.text-button-uppercase} — Variant of {component.text-button} with explicit text-transform: uppercase. Same token values otherwise. Creates the control-label appearance for language menus.

{component.input-code} — Large text input for room codes (observed in DOM but not visible in screenshot state). Background is {colors.canvas} (gray #f2f2f4)—distinguishing it from white surfaces. Text is {colors.body} at {typography.input-lg} (30px—very large, for room code readability across a room). Border-radius {rounded.md} (12px). Height 56px accommodates the large type. No visible border (border: 0px).

{component.input-code-focus} — Focus state for code input. Background shifts to {colors.surface} (white), creating a "lit up" effect that indicates focus. All other properties maintained.

Containers & Panels

{component.panel-card} — Standard content card/container. White background ({colors.surface}), body text color, {typography.body-md} type. Rounded to {rounded.lg} (20px). Padding {spacing.lg} (8px). Would carry {extensions.shadows.md} shadow when elevated (inferred from shadow usage count of 10 in CSS).

{component.panel-card-border} — Variant of panel card with visible border (class: border). Same white background, {rounded.xl} (30px)—more rounded than the basic card. Used for the discovery wrapper in this implementation.

{component.dialog-backdrop} — Full-screen overlay behind modals. Background is {colors.surface-overlay} at 50% opacity gray. Covers entire viewport (full class). Centers its child content.

{component.dialog-paper} — The actual modal surface appearing atop the backdrop. White background, body text, {typography.body-md}. Rounded to {rounded.lg} (20px). Generous padding of {spacing.xxl} (14px). Max-width constrained (inferred ~480px). Carries {extensions.shadows.md} for strong elevation separation from backdrop content.

{component.dialog-form} — Form container within dialogs. Transparent background (lets paper show through). Centers content via text-center class.

Informational

{component.traffic-notice} — The small-print footer note: "Traffic is routed through the server if WebRTC is not available." Renders in {colors.muted} gray at {typography.caption} (12px). Padding {spacing.lg} (8px). Multiple <span> elements allow for potential highlighting of specific phrases.

Icons

{component.icon-radar} — The central 64px radar/wifi icon in the footer. Rendered in {colors.ink} (brand blue). Custom SVG (not from a library). Circular with concentric arcs suggesting broadcast/signal.

{component.edit-icon} — Small 16px pencil icon adjacent to device name. Color {colors.body}. Triggers device name editing.

Do's and Don'ts

Do

  • Do use {colors.ink} (blue #4285f4) for primary headlines—this is intentional brand integration, not a link styling error. The blue headline signals "the product is speaking."
  • Do apply 18px letter-spacing ({typography.display-xl}.letterSpacing) to any room code or large numeric display—this creates the instrument-readout aesthetic essential to the technical voice.
  • Do reserve {typography.button-label} (12px/700/upercase) exclusively for control labels like language selectors and status badges—this creates a distinct "micro-ui" dialect.
  • Do use {colors.canvas} (#f2f2f2) as input field backgrounds ({component.input-code}) and shift to {colors.surface} (white) on focus—this creates clear focus signaling without borders.
  • Do wrap status information in {rounded.xl} (30px) containers like {component.discovery-wrapper}—the extra rounding signals "informational capsule" versus "actionable card."
  • Do keep the header background transparent—letting the canvas show through maintains the open, uncontained feeling of the interface.
  • Do use {colors.surface-muted} (#757575) for inline value highlights like the device name—this creates a "tagged" appearance without using brand color.
  • Do apply {rounded.pill} (9999px) to any boolean state indicator (on/off, connected/discovered)—pills universally read as "status badge" in this system.
  • Do center-align all hero and footer content—the radial symmetry of the interface demands center alignment to match the radar visualization.
  • Do use the triple-layered Material shadow ({extensions.shadows.md}) for any elevated panel or dialog—this is the sole shadow in the system and should remain consistent.

Don't

  • Don't apply bold weight (700) to body text or headings—the system maxes out at 400 for content typography. Emphasis comes from color and size, not weight.
  • Don't use sharp corners (0px radius) on content containers—only {component.nav-icon-button} uses square corners as a deliberate "chrome vs. content" signal.
  • Don't place {colors.primary} (blue) backgrounds on large areas—reserve brand-color backgrounds for small badges and interactive elements. Large blue blocks would overwhelm the restrained palette.
  • Don't add visible borders to input fields—the {component.input-code} uses background color change (canvas → white) for focus indication, not borders.
  • Don't left-align the hero message—the center alignment is architecturally tied to the radar visualization beneath it.
  • Don't introduce new font families—Open Sans handles Latin, Cyrillic, and Arabic; adding a second face would fracture the neutral voice.
  • Don't use {colors.ink} for body text—{colors.ink} is semantically "brand/headline" color. Body text must use {colors.body} (#333333).
  • Don't round the navigation icon buttons—even though the rest of the system is rounded, the sharp 40×40px squares signal "utility tools" and should remain unrounded.
  • Don't pad the discovery wrapper less than {spacing.base} (7px) vertically—the pill-shaped badge inside needs breathing room within its container.
  • Don't omit the concentric radar circles in empty states—they're not decorative optional; they're the primary visual element that transforms "empty" into "ready."

Motion & Animation

Transition Tokens

/* Core transitions extracted from computed styles */
--transition-all: all 0.3s ease-in-out;
--transition-background: background-color 0.5s ease;
--transition-transform: transform 0.3s ease-in-out;
--transition-clip-path: clip-path 0.8s cubic-bezier(0.77, 0, 0.175, 1);
--transition-default: 0.4s ease;

Keyframe Animations

  • fade-in — Opacity transition from 0 to 1 for the "no peers" message block and instructions panel. Creates a gentle entrance when the page loads or when devices disconnect.
  • pop — Scale-based entrance animation (likely for incoming peer notifications or file transfer completions). Adds playful energy to otherwise utilitarian interactions.

Interaction Patterns

  • Fade-in on state change: The x-no-peers and x-instructions containers carry a fade-in class, indicating they animate opacity when entering the DOM (e.g., when all peers disconnect).
  • Background color transitions: Buttons and inputs transition background-color over 0.3–0.5s, creating smooth state changes rather than hard cuts.
  • Clip-path animations: The 0.8s cubic-bezier(0.77, 0, 0.175, 1) timing on clip-path suggests reveal/hide animations for panels or dialogs—possibly a circular expand from the radar centerpoint.
  • Transform transitions: 0.3s transform easing indicates hover/focus scale effects on interactive elements (icon buttons, badges).
  • Theme toggle animation: The selected state of the theme toggle (filled pill) likely animates between positions using transform transitions.
  • Radar pulse (inferred): While not explicitly in keyframes, the central radar icon may have a CSS animation or JS-driven pulse to suggest "broadcasting/listening" activity.

The overall motion level is subtle—transitions serve functional clarity (state changes are perceptible) without drawing attention to themselves. The longest duration (0.8s on clip-path) suggests occasional "moment" animations for significant state changes (like a peer appearing), while micro-interactions stay under 0.4s.

Imagery Style

  • No photography: PairDrop uses zero photographic imagery. The visual vocabulary is entirely abstract/vector.
  • SVG iconography: Custom SVG icons for radar, navigation (video, link, bell, theme, accessibility, info), and editing (pencil). Icons are stroke-based, monochromatic (using currentColor).
  • Concentric circles: The signature decorative element—CSS or SVG circles in {colors.hairline} (#e0e0e0) creating a topographic/broadcast pattern. These are background decoration, not content.
  • Logo mark: The radar icon doubles as the brand logo (referenced in meta as logo_transparent_512x512.png).
  • Color treatment: All imagery is monochromatic, inheriting color from currentColor (typically {colors.body} or {colors.ink}).
  • Role: Imagery supports functionality—the radar icon indicates "discovery/broadcast," the edit icon indicates "mutability." Nothing is decorative for its own sake except the concentric circles, which serve the critical role of filling empty space meaningfully.
  • Scale: Icons range from 16px (edit) to 40px (nav icons) to 64px (hero radar)—scale correlates with importance/focus.
  • Favicon: 96×96 PNG (from meta), likely the radar icon in blue on transparent background.

Icon System

  • Library: Custom SVG (no detected library—Lucide, Heroicons, Material, etc. not present). All icons are inline SVGs or <use> references to a <defs> block (observed in footer SVG structure).
  • Specific icons observed:
    • Radar/Wifi broadcast: Concentric arc circles with center dot—primary brand icon, 64px in hero, also in footer as logo
    • Video/Camera: Top-left header icon (screen sharing or video chat reference)
    • Link chain: Connection/linking icon in header
    • Bell: Notifications icon in header
    • Sun/Moon (circle): Theme toggle (dark/light mode) in header
    • Text/Aa: Font/accessibility or language icon in header
    • Question mark (i): Help/info icon in header
    • Pencil/edit: Small 16px icon next to device name for renaming
  • Treatment: Stroke-based (not filled), using currentColor for color inheritance. Stroke width appears consistent (likely 1.5px or 2px). No filled-icon variants observed.
  • Size: Navigation icons are ~20-24px within 40×40px touch targets. Radar icon is 64px (hero) and scaled down for footer logo. Edit icon is 16px.
  • Alignment: Icons are center-aligned within their touch targets. Text icons (like the language button text) align baseline with icon baselines where they coexist.

Recommended Frontend Stack

- Framework:      Vanilla JavaScript / Web Components (observed custom elements: x-peers, x-no-peers, x-instructions, x-dialog, x-background, x-paper)
- Styling:        Vanilla CSS with BEM-like classes (.icon-button, .btn.fw.wrap, .panel, .fade-in, .center, .grow)
- Fonts:          Self-hosted Open Sans (TTF from /fonts/OpenSans/static/) with system font fallbacks
- Animation:      CSS transitions + @keyframes (fade-in, pop) — no JS animation library detected
- Icons:          Custom inline SVG with <defs> symbol reuse
- Component lib:  None (custom Web Component architecture)
- Build:          Unknown (possibly no build step — raw HTML/CSS/JS served directly)

Responsive Behavior

Breakpoints

| Name | Width | Key Changes | |---|---|---| | Mobile | < 640px | Header icons may wrap; central content column narrows to ~314px (observed); footer stacks vertically; radar circles may reduce in number or scale | | Tablet | 640px – 1024px | Content column expands; header maintains full icon set; spacing scales proportionally | | Desktop | 1024px – 1440px | Full header width (1440px max); generous whitespace around central column; optimal radar visibility | | Wide | > 1440px | Content may center with increased max-width; additional whitespace margins |

Note: Exact breakpoint values are inferred from container widths in extracted CSS (section: 314px, header: 1440px). Actual media queries were not visible in static extraction.

Touch Targets

  • {component.nav-icon-button}: 40×40px — meets WCAG AAA minimum (44×44px recommended, 40×44px is AA-compliant)
  • {component.text-button}: Height inferred ~28px (12px font + 7px padding × 2 + border) — may fall short of 44px; consider increasing vertical padding for mobile
  • {component.discovery-status-badge}: Height inferred ~26px (12px font + 3px padding × 2 + border) — compact; acceptable for non-critical status but small for primary touch
  • {component.input-code}: 56px height — exceeds 44px minimum, excellent for room code entry on touch devices
  • Edit icon (pencil): 16×16px — very small; likely relies on the parent {component.device-name-display}'s expanded hit area

Collapsing Strategy

  • Navigation header: Uses flex-wrap: wrap (observed wrap class), so icons will flow to multiple lines on narrow viewports rather than overflowing or hiding.
  • Hero columns: Single-column centered layout inherently responsive—no column collapse needed.
  • Footer panel: Already uses column (vertical) flex direction; will stack naturally on mobile.
  • Discovery wrapper: Uses row (horizontal) layout; on mobile may need to switch to column or allow badge wrapping.
  • Radar visualization: Concentric circles are likely position: absolute or fixed; should scale via transform: scale() or reduce circle count on mobile to prevent overflow.
  • Dialog papers: Constrained max-width (~480px) ensures modals remain usable on mobile with margin for dismissal area.

Image Behavior

  • Radar icon (SVG): Vector-based, scales infinitely without quality loss. Should use max-width: 100% and appropriate viewBox for responsive sizing.
  • Concentric circles: If CSS-generated (border-radius: 50%), they respond to container size. If SVG, they scale with viewBox.
  • Favicon/logo: Raster PNG (96×96, 512×512); served at fixed sizes, not responsive.
  • No raster photography: No <img> elements to manage responsively.

Iteration Guide

  1. Start with the canvas: Set background-color: {colors.canvas} (#f2f2f2) on <body>. Every surface builds from this neutral gray field.

  2. Implement the header first: Build {component.top-nav} as a flex container with justify-content: flex-end and flex-wrap: wrap. Add 7–8 {component.nav-icon-button} instances (40×40px, transparent, {colors.body} text). Implement the theme toggle as {component.nav-icon-button-selected} (pill shape, inverted colors).

  3. Build the hero center-stack: Create a centered column (max-width ~500px on mobile, expanding on desktop). Add {component.hero-headline} in {colors.ink} (blue!) at 22px, then {component.hero-subheadline} in {colors.body} at 14px. Center-align everything.

  4. Add the radar visualization: Implement concentric circles using either SVG <circle> elements or CSS border-radius: 50% pseudo-elements. Color them {colors.hairline} (#e0e0e0). Place the {component.icon-radar} (64px, blue) at center. Apply fade-in animation to the container.

  5. Build the footer identity panel: Create {component.footer-panel} as a column flex container at the bottom. Add {component.device-name-display} with the highlighted value using {colors.surface-muted} background. Then {component.discovery-wrapper} (white, {rounded.xl}) containing the label and {component.discovery-status-badge} (blue pill, white text, uppercase-bold 12px).

  6. Implement the dialog system: Create {component.dialog-backdrop} (fullscreen, 50% black overlay) that centers {component.dialog-paper} (white, {rounded.lg}, shadow {extensions.shadows.md}). Use clip-path transitions for enter/exit animations (0.8s cubic-bezier).

  7. Style forms and inputs: Build {component.input-code} with {colors.canvas} background, 30px font size, {rounded.md}. On :focus, transition background to {colors.surface} (white) over 0.3s. Never add borders.

  8. Apply typography precisely: Use {typography.display-xl} (45px, 18px letter-spacing) ONLY for room codes or large numerics. Use {typography.title-md} (22px, blue) for the primary headline. Keep body text at 14px/400 in {colors.body}. Reserve 12px/700/upercase for {typography.button-label} on controls.

  9. Add motion last: After static layout is perfect, add CSS transitions: all 0.3s ease-in-out on interactive elements, background-color 0.5s on surfaces, clip-path 0.8s cubic-bezier(0.77, 0, 0.175, 1) on reveals. Add @keyframes fade-in for the no-peers message.

  10. Test with real content: Verify the system works when devices actually appear (peer cards), when files are transferring (progress indicators), and when errors occur (apply {colors.error}, {colors.warning}, {colors.success} tokens). The empty state in the screenshot is only one of several states.

Font Setup: Self-host OpenSans-Medium.ttf (and ideally Light, Regular, Bold weights) from /fonts/OpenSans/static/. Define CSS variables:

:root {
  --font-family-base: "Open Sans", -apple-system, BlinkMacSystemFont, sans-serif;
}
body { font-family: var(--font-family-base); }

If unable to self-host, load from Google Fonts: https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap.

Known Gaps

  • Hover states: Per the no-hover policy, all :hover styles are undocumented. The frontmatter includes {colors.primary-hover} and {colors.primary-active} as guidance, but exact hover treatments (background tints? underline appearance? scale transforms?) must be designed at implementation time.
  • Peer card components: When other devices appear, they render as "peer cards"—their structure, layout, and styling are not visible in the empty-state screenshot. Inferred properties: white background, rounded corners, device name, avatar placeholder, possibly transfer progress indicators.
  • File transfer UI: The actual file sending/receiving interface (progress bars, file type icons, cancel buttons, completion states) is not captured in this screenshot. Semantic colors ({colors.success}, {colors.warning}, {colors.error}) are provided for these states.
  • Loading/skeleton states: No loading skeletons, spinners, or pending states were visible. Recommended: use the pop keyframe animation for new peer appearances, fade-in for content loads.
  • Mobile navigation collapse: How the header behaves below ~480px (hamburger menu? scrollable icon row? hidden utilities?) is not visible.
  • Dark mode: The theme toggle icon (sun/moon) indicates dark mode exists, but no dark-mode token values (dark canvas, dark surface, light text) were extractable from the light-mode screenshot. The extensions.mode is documented as "light"; dark mode requires a complementary token set.
  • Keyboard focus indicators: Focus rings (outline offset, color, radius) were not visible in static extraction. Recommend: 2px solid {colors.primary} outline with 2px offset, matching the brand color for accessibility.
  • Room code entry flow: The {component.input-code} (30px font, 56px height) was observed in DOM but the surrounding UI (dialog title, submit button, "share this code" instructions) was not in the visible viewport.
  • Internationalization layout: The interface supports Arabic (RTL?) and Cyrillic scripts (observed in button text). RTL layout behavior, text expansion for German/Finnish translations, and font-fallback rendering for CJK characters are unknown.
  • Exact shadow usage: The Material-style shadow ({extensions.shadows.md}) appeared 10 times in CSS, but which specific components receive it (all panels? only dialogs? elevated peer cards?) requires runtime observation or source code review.