commit 92de2ea68da0b476dbfa8178adce9f45833aaf08 Author: alexandrev-tibco Date: Tue Jan 13 17:29:39 2026 +0100 init diff --git a/about.html b/about.html new file mode 100644 index 0000000..000e6bd --- /dev/null +++ b/about.html @@ -0,0 +1,160 @@ + + + + + + About — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+

Our story

+

PorfolioJournal started with a simple idea: portfolio tracking should feel more like a thoughtful journal than a trading terminal. Monthly check-ins create space for reflection, helping investors learn from their decisions without the noise of daily volatility.

+ +

Values

+
    +
  • Calm over noise: We encourage intentional, long-term habits.
  • +
  • Privacy by default: Your data stays on your device unless you choose to sync it.
  • +
  • Clarity first: Clear, readable insights beat complex dashboards.
  • +
  • Ownership: Export and control your data at any time.
  • +
+ +

Roadmap

+
+
+

Next up

+

More goal templates, improved streak insights, and smarter check-in reminders.

+
+
+

Later this year

+

Custom analytics dashboards, better forecasting, and richer portfolio summaries.

+
+
+ +

Get in touch

+

Have ideas or feedback? Email us at support@portfoliojournal.app.

+
+
+
+
+ + + + diff --git a/assets/css/style.css b/assets/css/style.css new file mode 100644 index 0000000..fd27b17 --- /dev/null +++ b/assets/css/style.css @@ -0,0 +1,1733 @@ +/** + * PortfolioJournal - Apple-inspired Design System + * Clean, minimal, accessible + */ + +/* ======================================== + CSS Custom Properties (Design Tokens) + ======================================== */ + +:root { + /* Colors - Light Mode */ + --color-bg: #ffffff; + --color-bg-secondary: #f5f5f7; + --color-bg-tertiary: #fafafa; + --color-surface: #ffffff; + --color-surface-elevated: #ffffff; + + --color-text: #1d1d1f; + --color-text-secondary: #6e6e73; + --color-text-tertiary: #86868b; + + --color-primary: #0071e3; + --color-primary-hover: #0077ed; + --color-primary-active: #006edb; + + --color-accent: #34c759; + --color-accent-secondary: #5856d6; + --color-warning: #ff9500; + --color-error: #ff3b30; + + --color-border: rgba(0, 0, 0, 0.08); + --color-border-strong: rgba(0, 0, 0, 0.12); + --color-divider: rgba(0, 0, 0, 0.06); + + /* Gradients */ + --gradient-hero: linear-gradient(180deg, #f5f5f7 0%, #ffffff 100%); + --gradient-card: linear-gradient(145deg, #ffffff 0%, #fafafa 100%); + --gradient-accent: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --gradient-blob-1: radial-gradient(circle at 30% 20%, rgba(102, 126, 234, 0.08) 0%, transparent 50%); + --gradient-blob-2: radial-gradient(circle at 70% 80%, rgba(118, 75, 162, 0.06) 0%, transparent 50%); + + /* Shadows */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12); + --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.16); + --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.06), 0 0 1px rgba(0, 0, 0, 0.08); + --shadow-card-hover: 0 8px 24px rgba(0, 0, 0, 0.1), 0 0 1px rgba(0, 0, 0, 0.1); + + /* Typography */ + --font-sans: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; + --font-mono: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, 'Cascadia Code', monospace; + + --font-size-xs: 0.75rem; + --font-size-sm: 0.875rem; + --font-size-base: 1rem; + --font-size-lg: 1.125rem; + --font-size-xl: 1.25rem; + --font-size-2xl: 1.5rem; + --font-size-3xl: 2rem; + --font-size-4xl: 2.5rem; + --font-size-5xl: 3rem; + --font-size-6xl: 3.5rem; + + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + + --line-height-tight: 1.1; + --line-height-snug: 1.25; + --line-height-normal: 1.5; + --line-height-relaxed: 1.625; + + --letter-spacing-tight: -0.025em; + --letter-spacing-normal: 0; + --letter-spacing-wide: 0.025em; + + /* Spacing */ + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.25rem; + --space-6: 1.5rem; + --space-8: 2rem; + --space-10: 2.5rem; + --space-12: 3rem; + --space-16: 4rem; + --space-20: 5rem; + --space-24: 6rem; + --space-32: 8rem; + + /* Border Radius */ + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; + --radius-xl: 20px; + --radius-2xl: 28px; + --radius-full: 9999px; + + /* Transitions */ + --transition-fast: 150ms ease; + --transition-base: 250ms ease; + --transition-slow: 350ms ease; + --transition-bounce: 350ms cubic-bezier(0.34, 1.56, 0.64, 1); + + /* Z-index */ + --z-dropdown: 100; + --z-sticky: 200; + --z-modal: 300; + --z-toast: 400; + + /* Layout */ + --max-width-content: 980px; + --max-width-text: 680px; + --nav-height: 52px; +} + +/* Dark Mode */ +[data-theme="dark"] { + --color-bg: #000000; + --color-bg-secondary: #1c1c1e; + --color-bg-tertiary: #2c2c2e; + --color-surface: #1c1c1e; + --color-surface-elevated: #2c2c2e; + + --color-text: #f5f5f7; + --color-text-secondary: #a1a1a6; + --color-text-tertiary: #8e8e93; + + --color-primary: #0a84ff; + --color-primary-hover: #409cff; + --color-primary-active: #0077ed; + + --color-accent: #30d158; + --color-accent-secondary: #5e5ce6; + + --color-border: rgba(255, 255, 255, 0.1); + --color-border-strong: rgba(255, 255, 255, 0.16); + --color-divider: rgba(255, 255, 255, 0.08); + + --gradient-hero: linear-gradient(180deg, #1c1c1e 0%, #000000 100%); + --gradient-card: linear-gradient(145deg, #2c2c2e 0%, #1c1c1e 100%); + --gradient-blob-1: radial-gradient(circle at 30% 20%, rgba(102, 126, 234, 0.12) 0%, transparent 50%); + --gradient-blob-2: radial-gradient(circle at 70% 80%, rgba(118, 75, 162, 0.1) 0%, transparent 50%); + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5); + --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.6); + --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(255, 255, 255, 0.05); + --shadow-card-hover: 0 8px 24px rgba(0, 0, 0, 0.4), 0 0 1px rgba(255, 255, 255, 0.08); +} + +/* ======================================== + Reset & Base Styles + ======================================== */ + +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + font-size: 16px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; + scroll-behavior: smooth; +} + +body { + font-family: var(--font-sans); + font-size: var(--font-size-base); + font-weight: var(--font-weight-normal); + line-height: var(--line-height-normal); + color: var(--color-text); + background-color: var(--color-bg); + min-height: 100vh; + overflow-x: hidden; +} + +/* Background blobs */ +body::before, +body::after { + content: ''; + position: fixed; + inset: 0; + pointer-events: none; + z-index: -1; +} + +body::before { + background: var(--gradient-blob-1); +} + +body::after { + background: var(--gradient-blob-2); +} + +img, picture, video, canvas, svg { + display: block; + max-width: 100%; +} + +a { + color: var(--color-primary); + text-decoration: none; + transition: color var(--transition-fast); +} + +a:hover { + color: var(--color-primary-hover); +} + +a:focus-visible { + outline: 2px solid var(--color-primary); + outline-offset: 2px; + border-radius: var(--radius-sm); +} + +ul, ol { + list-style: none; +} + +button { + font-family: inherit; + font-size: inherit; + cursor: pointer; + border: none; + background: none; +} + +button:focus-visible { + outline: 2px solid var(--color-primary); + outline-offset: 2px; + border-radius: var(--radius-sm); +} + +input, textarea, select { + font-family: inherit; + font-size: inherit; +} + +/* Selection */ +::selection { + background-color: var(--color-primary); + color: white; +} + +/* ======================================== + Typography + ======================================== */ + +h1, h2, h3, h4, h5, h6 { + font-weight: var(--font-weight-semibold); + line-height: var(--line-height-tight); + letter-spacing: var(--letter-spacing-tight); + color: var(--color-text); +} + +h1 { + font-size: var(--font-size-5xl); + font-weight: var(--font-weight-bold); +} + +h2 { + font-size: var(--font-size-4xl); +} + +h3 { + font-size: var(--font-size-2xl); +} + +h4 { + font-size: var(--font-size-xl); +} + +h5 { + font-size: var(--font-size-lg); +} + +h6 { + font-size: var(--font-size-base); +} + +p { + color: var(--color-text-secondary); + line-height: var(--line-height-relaxed); +} + +.text-sm { + font-size: var(--font-size-sm); +} + +.text-lg { + font-size: var(--font-size-lg); +} + +.text-center { + text-align: center; +} + +.text-secondary { + color: var(--color-text-secondary); +} + +.text-tertiary { + color: var(--color-text-tertiary); +} + +/* ======================================== + Layout + ======================================== */ + +.container { + width: 100%; + max-width: var(--max-width-content); + margin: 0 auto; + padding: 0 var(--space-6); +} + +.container-narrow { + max-width: var(--max-width-text); +} + +.section { + padding: var(--space-20) 0; +} + +.section-lg { + padding: var(--space-24) 0; +} + +@media (max-width: 768px) { + .section { + padding: var(--space-12) 0; + } + + .section-lg { + padding: var(--space-16) 0; + } +} + +/* ======================================== + Navigation + ======================================== */ + +.nav { + position: fixed; + top: 0; + left: 0; + right: 0; + height: var(--nav-height); + background: rgba(255, 255, 255, 0.72); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); + border-bottom: 1px solid var(--color-border); + z-index: var(--z-sticky); +} + +[data-theme="dark"] .nav { + background: rgba(29, 29, 31, 0.72); +} + +.nav-inner { + display: flex; + align-items: center; + justify-content: space-between; + height: 100%; + max-width: var(--max-width-content); + margin: 0 auto; + padding: 0 var(--space-6); +} + +.nav-logo { + display: flex; + align-items: center; + gap: var(--space-3); + font-weight: var(--font-weight-semibold); + font-size: var(--font-size-lg); + color: var(--color-text); +} + +.nav-logo:hover { + color: var(--color-text); +} + +.nav-logo svg { + width: 28px; + height: 28px; +} + +.nav-links { + display: flex; + align-items: center; + gap: var(--space-1); +} + +.nav-link { + padding: var(--space-2) var(--space-4); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--color-text-secondary); + border-radius: var(--radius-full); + transition: all var(--transition-fast); +} + +.nav-link:hover { + color: var(--color-text); + background: var(--color-bg-secondary); +} + +.nav-link.active { + color: var(--color-text); +} + +.nav-actions { + display: flex; + align-items: center; + gap: var(--space-2); +} + +.theme-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + color: var(--color-text-secondary); + border-radius: var(--radius-full); + transition: all var(--transition-fast); +} + +.theme-toggle:hover { + color: var(--color-text); + background: var(--color-bg-secondary); +} + +.mobile-menu-toggle { + display: none; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + color: var(--color-text-secondary); + border-radius: var(--radius-full); +} + +@media (max-width: 768px) { + .nav-links { + position: fixed; + top: var(--nav-height); + left: 0; + right: 0; + flex-direction: column; + padding: var(--space-4); + background: var(--color-bg); + border-bottom: 1px solid var(--color-border); + transform: translateY(-100%); + opacity: 0; + visibility: hidden; + transition: all var(--transition-base); + } + + .nav-links.open { + transform: translateY(0); + opacity: 1; + visibility: visible; + } + + .nav-link { + width: 100%; + padding: var(--space-3) var(--space-4); + text-align: center; + } + + .mobile-menu-toggle { + display: flex; + } +} + +/* ======================================== + Buttons + ======================================== */ + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--space-2); + padding: var(--space-3) var(--space-6); + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + line-height: 1; + border-radius: var(--radius-full); + transition: all var(--transition-fast); + white-space: nowrap; +} + +.btn-primary { + background: var(--color-primary); + color: white; +} + +.btn-primary:hover { + background: var(--color-primary-hover); + color: white; + transform: translateY(-1px); +} + +.btn-primary:active { + background: var(--color-primary-active); + transform: translateY(0); +} + +.btn-secondary { + background: var(--color-bg-secondary); + color: var(--color-text); +} + +.btn-secondary:hover { + background: var(--color-bg-tertiary); + color: var(--color-text); +} + +[data-theme="dark"] .btn-secondary { + background: var(--color-surface); +} + +[data-theme="dark"] .btn-secondary:hover { + background: var(--color-surface-elevated); +} + +.btn-outline { + background: transparent; + color: var(--color-primary); + border: 1px solid var(--color-primary); +} + +.btn-outline:hover { + background: var(--color-primary); + color: white; +} + +.btn-lg { + padding: var(--space-4) var(--space-8); + font-size: var(--font-size-lg); +} + +.btn-small { + padding: var(--space-2) var(--space-4); + font-size: var(--font-size-sm); +} + +.btn-icon { + width: 44px; + height: 44px; + padding: 0; +} + +/* App Store Button */ +.btn-appstore { + display: inline-flex; + align-items: center; + gap: var(--space-3); + padding: var(--space-3) var(--space-5); + background: var(--color-text); + color: var(--color-bg); + border-radius: var(--radius-md); + transition: all var(--transition-fast); +} + +.btn-appstore:hover { + opacity: 0.9; + color: var(--color-bg); + transform: translateY(-1px); +} + +.btn-appstore svg { + width: 24px; + height: 24px; +} + +.btn-appstore-text { + display: flex; + flex-direction: column; + align-items: flex-start; + text-align: left; +} + +.btn-appstore-text span:first-child { + font-size: var(--font-size-xs); + opacity: 0.8; +} + +.btn-appstore-text span:last-child { + font-size: var(--font-size-base); + font-weight: var(--font-weight-semibold); +} + +/* ======================================== + Hero Section + ======================================== */ + +.hero { + min-height: 100vh; + display: flex; + align-items: center; + padding-top: calc(var(--nav-height) + var(--space-12)); + padding-bottom: var(--space-12); + background: var(--gradient-hero); +} + +.hero-content { + text-align: center; + max-width: 720px; + margin: 0 auto; +} + +.hero-badge { + display: inline-flex; + align-items: center; + gap: var(--space-2); + padding: var(--space-2) var(--space-4); + margin-bottom: var(--space-6); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--color-text-secondary); + background: var(--color-bg-secondary); + border-radius: var(--radius-full); +} + +.hero-badge svg { + width: 16px; + height: 16px; +} + +.hero-title { + font-size: clamp(2.5rem, 8vw, 4.5rem); + font-weight: var(--font-weight-bold); + line-height: 1.05; + letter-spacing: -0.03em; + margin-bottom: var(--space-6); +} + +.hero-title-gradient { + background: var(--gradient-accent); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.hero-description { + font-size: var(--font-size-xl); + color: var(--color-text-secondary); + max-width: 540px; + margin: 0 auto var(--space-10); + line-height: var(--line-height-relaxed); +} + +.hero-actions { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: var(--space-4); +} + +.hero-app-icon { + width: 120px; + height: 120px; + margin: 0 auto var(--space-8); + border-radius: var(--radius-2xl); + background: var(--gradient-accent); + box-shadow: var(--shadow-lg); + display: flex; + align-items: center; + justify-content: center; +} + +.hero-app-icon svg { + width: 60px; + height: 60px; + color: white; +} + +/* ======================================== + Features Section + ======================================== */ + +.features { + background: var(--color-bg); +} + +.features-header { + text-align: center; + max-width: 600px; + margin: 0 auto var(--space-16); +} + +.features-header h2 { + margin-bottom: var(--space-4); +} + +.features-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-6); +} + +@media (max-width: 968px) { + .features-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 640px) { + .features-grid { + grid-template-columns: 1fr; + } +} + +.feature-card { + padding: var(--space-8); + background: var(--gradient-card); + border: 1px solid var(--color-border); + border-radius: var(--radius-xl); + transition: all var(--transition-base); +} + +.feature-card:hover { + border-color: var(--color-border-strong); + box-shadow: var(--shadow-card-hover); + transform: translateY(-2px); +} + +.feature-icon { + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + margin-bottom: var(--space-4); + background: var(--color-bg-secondary); + border-radius: var(--radius-lg); + color: var(--color-primary); +} + +[data-theme="dark"] .feature-icon { + background: var(--color-surface-elevated); +} + +.feature-icon svg { + width: 24px; + height: 24px; +} + +.feature-card h3 { + font-size: var(--font-size-lg); + margin-bottom: var(--space-2); +} + +.feature-card p { + font-size: var(--font-size-sm); +} + +/* Premium Features */ +.premium-badge { + display: inline-flex; + align-items: center; + gap: var(--space-1); + padding: var(--space-1) var(--space-2); + margin-bottom: var(--space-3); + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + color: var(--color-accent-secondary); + background: rgba(88, 86, 214, 0.1); + border-radius: var(--radius-full); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +[data-theme="dark"] .premium-badge { + background: rgba(94, 92, 230, 0.2); +} + +/* ======================================== + Screenshots Section + ======================================== */ + +.screenshots { + background: var(--color-bg-secondary); + overflow: hidden; +} + +.screenshots-header { + text-align: center; + max-width: 600px; + margin: 0 auto var(--space-12); +} + +.screenshots-gallery { + display: flex; + gap: var(--space-6); + padding: var(--space-4) 0; + overflow-x: auto; + scroll-snap-type: x mandatory; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; +} + +.screenshots-gallery::-webkit-scrollbar { + display: none; +} + +.screenshot-item { + flex: 0 0 auto; + scroll-snap-align: center; +} + +.screenshot-item:first-child { + margin-left: calc((100vw - var(--max-width-content)) / 2 + var(--space-6)); +} + +.screenshot-item:last-child { + margin-right: calc((100vw - var(--max-width-content)) / 2 + var(--space-6)); +} + +@media (max-width: 980px) { + .screenshot-item:first-child { + margin-left: var(--space-6); + } + + .screenshot-item:last-child { + margin-right: var(--space-6); + } +} + +.screenshot-frame { + width: 260px; + height: 520px; + background: var(--color-surface); + border-radius: var(--radius-2xl); + box-shadow: var(--shadow-lg); + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + color: var(--color-text-tertiary); + font-size: var(--font-size-sm); +} + +/* ======================================== + Built for iOS Section + ======================================== */ + +.ios-features { + background: var(--color-bg); +} + +.ios-features-header { + text-align: center; + max-width: 600px; + margin: 0 auto var(--space-12); +} + +.ios-features-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-6); +} + +@media (max-width: 968px) { + .ios-features-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 480px) { + .ios-features-grid { + grid-template-columns: 1fr; + } +} + +.ios-feature { + text-align: center; + padding: var(--space-6); +} + +.ios-feature-icon { + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 56px; + margin: 0 auto var(--space-4); + background: var(--color-bg-secondary); + border-radius: var(--radius-lg); + color: var(--color-primary); +} + +[data-theme="dark"] .ios-feature-icon { + background: var(--color-surface); +} + +.ios-feature-icon svg { + width: 28px; + height: 28px; +} + +.ios-feature h4 { + margin-bottom: var(--space-2); +} + +.ios-feature p { + font-size: var(--font-size-sm); +} + +/* ======================================== + Testimonials Section + ======================================== */ + +.testimonials { + background: var(--color-bg-secondary); +} + +.testimonials-header { + text-align: center; + max-width: 600px; + margin: 0 auto var(--space-12); +} + +.testimonials-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--space-6); +} + +@media (max-width: 968px) { + .testimonials-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 640px) { + .testimonials-grid { + grid-template-columns: 1fr; + } +} + +.testimonial-card { + padding: var(--space-6); + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-xl); +} + +.testimonial-stars { + display: flex; + gap: var(--space-1); + margin-bottom: var(--space-4); + color: var(--color-warning); +} + +.testimonial-stars svg { + width: 16px; + height: 16px; + fill: currentColor; +} + +.testimonial-text { + font-size: var(--font-size-base); + color: var(--color-text); + margin-bottom: var(--space-4); + line-height: var(--line-height-relaxed); +} + +.testimonial-author { + font-size: var(--font-size-sm); + color: var(--color-text-tertiary); +} + +/* ======================================== + FAQ Section + ======================================== */ + +.faq { + background: var(--color-bg); +} + +.faq-header { + text-align: center; + max-width: 600px; + margin: 0 auto var(--space-12); +} + +.faq-list { + max-width: 680px; + margin: 0 auto; +} + +.faq-item { + border-bottom: 1px solid var(--color-border); +} + +.faq-item:first-child { + border-top: 1px solid var(--color-border); +} + +.faq-question { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: var(--space-5) 0; + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + color: var(--color-text); + text-align: left; + cursor: pointer; +} + +.faq-question::after { + content: '+'; + font-size: var(--font-size-xl); + font-weight: var(--font-weight-normal); + color: var(--color-text-tertiary); + transition: transform var(--transition-fast); +} + +.faq-item.open .faq-question::after { + content: '-'; +} + +.faq-answer { + max-height: 0; + overflow: hidden; + transition: max-height var(--transition-base); +} + +.faq-item.open .faq-answer { + max-height: 500px; +} + +.faq-answer-inner { + padding-bottom: var(--space-5); + color: var(--color-text-secondary); + line-height: var(--line-height-relaxed); +} + +/* ======================================== + CTA Section + ======================================== */ + +.cta { + background: var(--color-bg-secondary); + text-align: center; +} + +.cta-content { + max-width: 600px; + margin: 0 auto; +} + +.cta h2 { + margin-bottom: var(--space-4); +} + +.cta p { + margin-bottom: var(--space-8); +} + +.cta-actions { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: var(--space-4); +} + +/* ======================================== + Footer + ======================================== */ + +.footer { + background: var(--color-bg); + border-top: 1px solid var(--color-border); + padding: var(--space-16) 0 var(--space-8); +} + +.footer-grid { + display: grid; + grid-template-columns: 2fr repeat(3, 1fr); + gap: var(--space-12); + margin-bottom: var(--space-12); +} + +@media (max-width: 768px) { + .footer-grid { + grid-template-columns: 1fr 1fr; + gap: var(--space-8); + } +} + +@media (max-width: 480px) { + .footer-grid { + grid-template-columns: 1fr; + } +} + +.footer-brand { + max-width: 280px; +} + +.footer-logo { + display: flex; + align-items: center; + gap: var(--space-3); + font-weight: var(--font-weight-semibold); + font-size: var(--font-size-lg); + color: var(--color-text); + margin-bottom: var(--space-4); +} + +.footer-logo svg { + width: 32px; + height: 32px; +} + +.footer-brand p { + font-size: var(--font-size-sm); + margin-bottom: var(--space-4); +} + +.footer-column h5 { + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--color-text-tertiary); + margin-bottom: var(--space-4); +} + +.footer-links { + display: flex; + flex-direction: column; + gap: var(--space-3); +} + +.footer-link { + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +.footer-link:hover { + color: var(--color-text); +} + +.footer-bottom { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: var(--space-4); + padding-top: var(--space-8); + border-top: 1px solid var(--color-border); +} + +.footer-copyright { + font-size: var(--font-size-sm); + color: var(--color-text-tertiary); +} + +.footer-legal { + display: flex; + gap: var(--space-6); +} + +.footer-legal a { + font-size: var(--font-size-sm); + color: var(--color-text-tertiary); +} + +.footer-legal a:hover { + color: var(--color-text-secondary); +} + +/* ======================================== + Page Header (for inner pages) + ======================================== */ + +.page-header { + padding-top: calc(var(--nav-height) + var(--space-16)); + padding-bottom: var(--space-12); + background: var(--gradient-hero); + text-align: center; +} + +.page-header h1 { + margin-bottom: var(--space-4); +} + +.page-header p { + font-size: var(--font-size-lg); + max-width: 600px; + margin: 0 auto; +} + +.page-header-meta { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: var(--space-4); + margin-top: var(--space-4); + font-size: var(--font-size-sm); + color: var(--color-text-tertiary); +} + +/* ======================================== + Content Styles (for policy pages) + ======================================== */ + +.content { + padding: var(--space-16) 0; +} + +.content-body { + max-width: var(--max-width-text); + margin: 0 auto; +} + +.content-body h2 { + font-size: var(--font-size-2xl); + margin-top: var(--space-12); + margin-bottom: var(--space-4); +} + +.content-body h2:first-child { + margin-top: 0; +} + +.content-body h3 { + font-size: var(--font-size-xl); + margin-top: var(--space-8); + margin-bottom: var(--space-3); +} + +.content-body p { + margin-bottom: var(--space-4); +} + +.content-body ul, +.content-body ol { + margin-bottom: var(--space-4); + padding-left: var(--space-6); +} + +.content-body ul { + list-style: disc; +} + +.content-body ol { + list-style: decimal; +} + +.content-body li { + margin-bottom: var(--space-2); + color: var(--color-text-secondary); +} + +.content-body a { + text-decoration: underline; + text-underline-offset: 2px; +} + +.content-body strong { + font-weight: var(--font-weight-semibold); + color: var(--color-text); +} + +.content-body code { + padding: var(--space-1) var(--space-2); + font-family: var(--font-mono); + font-size: 0.875em; + background: var(--color-bg-secondary); + border-radius: var(--radius-sm); +} + +/* Summary Box */ +.summary-box { + padding: var(--space-6); + margin-bottom: var(--space-8); + background: var(--color-bg-secondary); + border-radius: var(--radius-lg); + border-left: 4px solid var(--color-primary); +} + +[data-theme="dark"] .summary-box { + background: var(--color-surface); +} + +.summary-box h3 { + font-size: var(--font-size-lg); + margin-top: 0; + margin-bottom: var(--space-3); +} + +.summary-box ul { + margin-bottom: 0; +} + +.summary-box li { + margin-bottom: var(--space-2); +} + +.summary-box li:last-child { + margin-bottom: 0; +} + +/* Info Box */ +.info-box { + padding: var(--space-4); + margin: var(--space-6) 0; + background: rgba(0, 113, 227, 0.08); + border-radius: var(--radius-md); + border: 1px solid rgba(0, 113, 227, 0.2); +} + +[data-theme="dark"] .info-box { + background: rgba(10, 132, 255, 0.1); + border-color: rgba(10, 132, 255, 0.2); +} + +.info-box p { + margin-bottom: 0; + font-size: var(--font-size-sm); + color: var(--color-text); +} + +/* Warning Box */ +.warning-box { + padding: var(--space-4); + margin: var(--space-6) 0; + background: rgba(255, 149, 0, 0.08); + border-radius: var(--radius-md); + border: 1px solid rgba(255, 149, 0, 0.2); +} + +.warning-box p { + margin-bottom: 0; + font-size: var(--font-size-sm); + color: var(--color-text); +} + +/* Steps List */ +.steps-list { + counter-reset: step; + list-style: none; + padding-left: 0; +} + +.steps-list li { + position: relative; + padding-left: var(--space-10); + margin-bottom: var(--space-4); +} + +.steps-list li::before { + counter-increment: step; + content: counter(step); + position: absolute; + left: 0; + top: 0; + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + color: var(--color-primary); + background: rgba(0, 113, 227, 0.1); + border-radius: var(--radius-full); +} + +[data-theme="dark"] .steps-list li::before { + background: rgba(10, 132, 255, 0.15); +} + +/* ======================================== + Cards Grid (for support, press kit) + ======================================== */ + +.cards-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: var(--space-6); +} + +@media (max-width: 640px) { + .cards-grid { + grid-template-columns: 1fr; + } +} + +.card { + padding: var(--space-6); + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-xl); + transition: all var(--transition-base); +} + +.card:hover { + border-color: var(--color-border-strong); + box-shadow: var(--shadow-card); +} + +.card-icon { + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + margin-bottom: var(--space-4); + background: var(--color-bg-secondary); + border-radius: var(--radius-lg); + color: var(--color-primary); +} + +[data-theme="dark"] .card-icon { + background: var(--color-surface-elevated); +} + +.card-icon svg { + width: 24px; + height: 24px; +} + +.card h3 { + font-size: var(--font-size-lg); + margin-bottom: var(--space-2); +} + +.card p { + font-size: var(--font-size-sm); + margin-bottom: var(--space-4); +} + +.card .btn { + margin-top: auto; +} + +/* ======================================== + Status Page + ======================================== */ + +.status-indicator { + display: flex; + align-items: center; + gap: var(--space-3); + padding: var(--space-4) var(--space-6); + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + margin-bottom: var(--space-8); +} + +.status-dot { + width: 12px; + height: 12px; + border-radius: var(--radius-full); + background: var(--color-accent); + animation: pulse 2s ease-in-out infinite; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + +.status-dot.warning { + background: var(--color-warning); +} + +.status-dot.error { + background: var(--color-error); +} + +.status-text { + font-weight: var(--font-weight-medium); +} + +.status-list { + margin-bottom: var(--space-8); +} + +.status-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-4) 0; + border-bottom: 1px solid var(--color-border); +} + +.status-item:first-child { + border-top: 1px solid var(--color-border); +} + +.status-item-name { + font-weight: var(--font-weight-medium); +} + +.status-item-status { + display: flex; + align-items: center; + gap: var(--space-2); + font-size: var(--font-size-sm); + color: var(--color-accent); +} + +.status-item-status.warning { + color: var(--color-warning); +} + +.status-item-status.error { + color: var(--color-error); +} + +/* ======================================== + Changelog + ======================================== */ + +.changelog-list { + max-width: var(--max-width-text); + margin: 0 auto; +} + +.changelog-entry { + padding: var(--space-8) 0; + border-bottom: 1px solid var(--color-border); +} + +.changelog-entry:first-child { + padding-top: 0; +} + +.changelog-header { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-3); + margin-bottom: var(--space-4); +} + +.changelog-version { + font-size: var(--font-size-xl); + font-weight: var(--font-weight-semibold); +} + +.changelog-date { + font-size: var(--font-size-sm); + color: var(--color-text-tertiary); +} + +.changelog-tag { + padding: var(--space-1) var(--space-2); + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + text-transform: uppercase; + letter-spacing: 0.5px; + border-radius: var(--radius-sm); +} + +.changelog-tag.new { + background: rgba(52, 199, 89, 0.1); + color: var(--color-accent); +} + +.changelog-tag.improved { + background: rgba(0, 113, 227, 0.1); + color: var(--color-primary); +} + +.changelog-tag.fixed { + background: rgba(255, 149, 0, 0.1); + color: var(--color-warning); +} + +.changelog-body ul { + list-style: disc; + padding-left: var(--space-6); +} + +.changelog-body li { + margin-bottom: var(--space-2); + color: var(--color-text-secondary); +} + +/* ======================================== + Press Kit + ======================================== */ + +.brand-colors { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: var(--space-4); + margin-top: var(--space-6); +} + +.color-swatch { + aspect-ratio: 1; + border-radius: var(--radius-lg); + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + padding: var(--space-3); + font-size: var(--font-size-xs); + font-family: var(--font-mono); + color: white; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); +} + +.icon-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); + gap: var(--space-4); + margin-top: var(--space-6); +} + +.icon-item { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--space-2); + padding: var(--space-4); + background: var(--color-bg-secondary); + border-radius: var(--radius-lg); +} + +.icon-item img, +.icon-item svg { + width: 64px; + height: 64px; + border-radius: var(--radius-md); +} + +.icon-item span { + font-size: var(--font-size-xs); + color: var(--color-text-tertiary); +} + +/* ======================================== + Cookie Notice + ======================================== */ + +.cookie-notice { + position: fixed; + bottom: var(--space-4); + left: var(--space-4); + right: var(--space-4); + max-width: 480px; + padding: var(--space-4); + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + z-index: var(--z-toast); +} + +.cookie-notice-content p { + margin-bottom: var(--space-3); + font-size: var(--font-size-sm); +} + +.cookie-notice-actions { + display: flex; + gap: var(--space-2); +} + +/* ======================================== + Utilities + ======================================== */ + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.skip-link { + position: absolute; + top: -40px; + left: 0; + padding: var(--space-2) var(--space-4); + background: var(--color-primary); + color: white; + z-index: 9999; + transition: top var(--transition-fast); +} + +.skip-link:focus { + top: 0; +} + +/* Print styles */ +@media print { + .nav, + .footer, + .cookie-notice, + .theme-toggle { + display: none; + } + + body { + background: white; + color: black; + } + + .page-header { + padding-top: var(--space-8); + } +} diff --git a/assets/icons/apple-touch-icon.svg b/assets/icons/apple-touch-icon.svg new file mode 100644 index 0000000..794a008 --- /dev/null +++ b/assets/icons/apple-touch-icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/icons/favicon.svg b/assets/icons/favicon.svg new file mode 100644 index 0000000..4585492 --- /dev/null +++ b/assets/icons/favicon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/images/app-icon.svg b/assets/images/app-icon.svg new file mode 100644 index 0000000..21ce47f --- /dev/null +++ b/assets/images/app-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/images/og-image.svg b/assets/images/og-image.svg new file mode 100644 index 0000000..629cadf --- /dev/null +++ b/assets/images/og-image.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + PorfolioJournal + Offline-first portfolio tracking with calm monthly check-ins. + diff --git a/assets/images/screenshots/screen-1.svg b/assets/images/screenshots/screen-1.svg new file mode 100644 index 0000000..577bc40 --- /dev/null +++ b/assets/images/screenshots/screen-1.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + Screenshot placeholder + Replace with real app screens + diff --git a/assets/images/screenshots/screen-2.svg b/assets/images/screenshots/screen-2.svg new file mode 100644 index 0000000..577bc40 --- /dev/null +++ b/assets/images/screenshots/screen-2.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + Screenshot placeholder + Replace with real app screens + diff --git a/assets/images/screenshots/screen-3.svg b/assets/images/screenshots/screen-3.svg new file mode 100644 index 0000000..577bc40 --- /dev/null +++ b/assets/images/screenshots/screen-3.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + Screenshot placeholder + Replace with real app screens + diff --git a/assets/images/screenshots/screen-4.svg b/assets/images/screenshots/screen-4.svg new file mode 100644 index 0000000..577bc40 --- /dev/null +++ b/assets/images/screenshots/screen-4.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + Screenshot placeholder + Replace with real app screens + diff --git a/assets/js/config.js b/assets/js/config.js new file mode 100644 index 0000000..c1d544c --- /dev/null +++ b/assets/js/config.js @@ -0,0 +1,28 @@ +/** + * PorfolioJournal Site Configuration + * Edit these values to customize the site + */ +const CONFIG = { + APP_NAME: 'PorfolioJournal', + TAGLINE: 'Your personal portfolio, thoughtfully tracked.', + DESCRIPTION: 'A calm, offline-first iOS app for tracking your portfolio with monthly check-ins, reflections, and long-term insights.', + APP_STORE_URL: 'https://apps.apple.com/app/porfoliojournal/id000000000', + SUPPORT_EMAIL: 'support@portfoliojournal.app', + COMPANY_NAME: 'PorfolioJournal', + WEBSITE_URL: 'https://portfoliojournal.app', + EFFECTIVE_DATE: 'today', + COPYRIGHT_YEAR: new Date().getFullYear(), + ENABLE_ANALYTICS: false, + ANALYTICS_ID: '', // Add your analytics ID if enabled + + // Social links (optional) + SOCIAL: { + TWITTER: '', + GITHUB: '', + MASTODON: '' + } +}; + +// Freeze config to prevent accidental modifications +Object.freeze(CONFIG); +Object.freeze(CONFIG.SOCIAL); diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..d8b9801 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,280 @@ +/** + * PortfolioJournal Main JavaScript + * Handles dark mode, navigation, and dynamic content + */ + +(function() { + 'use strict'; + + // Dark Mode Management + const DarkMode = { + STORAGE_KEY: 'pj-theme', + + init() { + const saved = localStorage.getItem(this.STORAGE_KEY); + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + + if (saved === 'dark' || (!saved && prefersDark)) { + document.documentElement.setAttribute('data-theme', 'dark'); + } else { + document.documentElement.setAttribute('data-theme', 'light'); + } + + // Listen for system preference changes + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { + if (!localStorage.getItem(this.STORAGE_KEY)) { + document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light'); + } + }); + }, + + toggle() { + const current = document.documentElement.getAttribute('data-theme'); + const next = current === 'dark' ? 'light' : 'dark'; + document.documentElement.setAttribute('data-theme', next); + localStorage.setItem(this.STORAGE_KEY, next); + this.updateToggleButton(); + }, + + updateToggleButton() { + const btn = document.querySelector('.theme-toggle'); + if (btn) { + const isDark = document.documentElement.getAttribute('data-theme') === 'dark'; + btn.setAttribute('aria-label', isDark ? 'Switch to light mode' : 'Switch to dark mode'); + btn.innerHTML = isDark ? this.getSunIcon() : this.getMoonIcon(); + } + }, + + getSunIcon() { + return ``; + }, + + getMoonIcon() { + return ``; + } + }; + + // Navigation Management + const Navigation = { + init() { + this.setActiveLink(); + this.setupMobileMenu(); + this.setupKeyboardNav(); + }, + + setActiveLink() { + const currentPath = window.location.pathname; + const links = document.querySelectorAll('.nav-link'); + + links.forEach(link => { + const href = link.getAttribute('href'); + const isActive = currentPath.endsWith(href) || + (href === 'index.html' && (currentPath === '/' || currentPath.endsWith('/'))); + + if (isActive) { + link.classList.add('active'); + link.setAttribute('aria-current', 'page'); + } + }); + }, + + setupMobileMenu() { + const toggle = document.querySelector('.mobile-menu-toggle'); + const nav = document.querySelector('.nav-links'); + + if (toggle && nav) { + toggle.addEventListener('click', () => { + const isOpen = nav.classList.toggle('open'); + toggle.setAttribute('aria-expanded', isOpen); + toggle.innerHTML = isOpen ? this.getCloseIcon() : this.getMenuIcon(); + }); + + // Close menu on link click + nav.querySelectorAll('a').forEach(link => { + link.addEventListener('click', () => { + nav.classList.remove('open'); + toggle.setAttribute('aria-expanded', 'false'); + toggle.innerHTML = this.getMenuIcon(); + }); + }); + } + }, + + setupKeyboardNav() { + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + const nav = document.querySelector('.nav-links'); + const toggle = document.querySelector('.mobile-menu-toggle'); + if (nav && nav.classList.contains('open')) { + nav.classList.remove('open'); + toggle.setAttribute('aria-expanded', 'false'); + toggle.innerHTML = this.getMenuIcon(); + } + } + }); + }, + + getMenuIcon() { + return ``; + }, + + getCloseIcon() { + return ``; + } + }; + + // Dynamic Content + const Content = { + init() { + this.insertYear(); + this.insertConfig(); + this.insertEffectiveDate(); + }, + + insertYear() { + document.querySelectorAll('[data-year]').forEach(el => { + el.textContent = CONFIG.COPYRIGHT_YEAR; + }); + }, + + insertConfig() { + document.querySelectorAll('[data-config]').forEach(el => { + const key = el.getAttribute('data-config'); + if (CONFIG[key]) { + if (el.tagName === 'A') { + el.href = CONFIG[key]; + } else { + el.textContent = CONFIG[key]; + } + } + }); + }, + + insertEffectiveDate() { + document.querySelectorAll('[data-effective-date]').forEach(el => { + const dateValue = CONFIG.EFFECTIVE_DATE === 'today' ? new Date() : new Date(CONFIG.EFFECTIVE_DATE); + const date = Number.isNaN(dateValue.getTime()) ? new Date() : dateValue; + el.textContent = date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + }); + }); + } + }; + + // Smooth Scroll + const SmoothScroll = { + init() { + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', (e) => { + const targetId = anchor.getAttribute('href'); + if (targetId === '#') return; + + const target = document.querySelector(targetId); + if (target) { + e.preventDefault(); + target.scrollIntoView({ behavior: 'smooth', block: 'start' }); + target.focus({ preventScroll: true }); + } + }); + }); + } + }; + + // Cookie Notice (only if analytics enabled) + const CookieNotice = { + STORAGE_KEY: 'pj-cookies-accepted', + + init() { + if (!CONFIG.ENABLE_ANALYTICS) return; + if (localStorage.getItem(this.STORAGE_KEY)) return; + + this.show(); + }, + + show() { + const notice = document.createElement('div'); + notice.className = 'cookie-notice'; + notice.innerHTML = ` + + `; + document.body.appendChild(notice); + }, + + accept() { + localStorage.setItem(this.STORAGE_KEY, 'true'); + this.hide(); + // Initialize analytics here if needed + }, + + decline() { + localStorage.setItem(this.STORAGE_KEY, 'false'); + this.hide(); + }, + + hide() { + const notice = document.querySelector('.cookie-notice'); + if (notice) notice.remove(); + } + }; + + // FAQ Accordion + const FAQ = { + init() { + document.querySelectorAll('.faq-question').forEach(question => { + question.addEventListener('click', () => { + const item = question.parentElement; + const isOpen = item.classList.contains('open'); + + // Close all others + document.querySelectorAll('.faq-item.open').forEach(openItem => { + openItem.classList.remove('open'); + openItem.querySelector('.faq-question').setAttribute('aria-expanded', 'false'); + }); + + // Toggle current + if (!isOpen) { + item.classList.add('open'); + question.setAttribute('aria-expanded', 'true'); + } + }); + + // Keyboard support + question.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + question.click(); + } + }); + }); + } + }; + + // Initialize everything on DOM ready + document.addEventListener('DOMContentLoaded', () => { + DarkMode.init(); + DarkMode.updateToggleButton(); + Navigation.init(); + Content.init(); + SmoothScroll.init(); + FAQ.init(); + CookieNotice.init(); + + // Setup theme toggle button + const themeToggle = document.querySelector('.theme-toggle'); + if (themeToggle) { + themeToggle.addEventListener('click', () => DarkMode.toggle()); + } + }); + + // Expose necessary functions globally + window.DarkMode = DarkMode; + window.CookieNotice = CookieNotice; +})(); diff --git a/changelog.html b/changelog.html new file mode 100644 index 0000000..3ebeac8 --- /dev/null +++ b/changelog.html @@ -0,0 +1,176 @@ + + + + + + Changelog — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+
+ v1.0.0 + Jan 15, 2025 + New +
+
+
    +
  • Initial release with monthly check-ins, snapshots, and goal tracking.
  • +
  • Offline-first storage with optional iCloud sync.
  • +
  • CSV and JSON export options.
  • +
+
+
+
+
+ v1.1.0 + Feb 10, 2025 + Improved +
+
+
    +
  • New dashboard view with cashflow vs growth breakdown.
  • +
  • Improved goal pacing indicators and streak tracking.
  • +
  • Performance tuning for large portfolios.
  • +
+
+
+
+
+ v1.1.1 + Mar 2, 2025 + Fixed +
+
+
    +
  • Fixed export formatting for decimal separators.
  • +
  • Resolved an issue with monthly reminder notifications.
  • +
+
+
+
+
+
+
+ + + + diff --git a/delete-data.html b/delete-data.html new file mode 100644 index 0000000..6cc2179 --- /dev/null +++ b/delete-data.html @@ -0,0 +1,155 @@ + + + + + + Delete Data — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+

Delete data on your device

+
    +
  1. Open PorfolioJournal on your iPhone or iPad.
  2. +
  3. Go to Settings.
  4. +
  5. Select “Delete All Data”.
  6. +
  7. Confirm the deletion. This immediately removes local portfolio data and journal entries.
  8. +
+ +

Delete iCloud data (if enabled)

+
    +
  1. Open the app and disable iCloud sync in Settings.
  2. +
  3. Open iOS Settings > Apple ID > iCloud > Manage Storage.
  4. +
  5. Locate PorfolioJournal and delete its iCloud data.
  6. +
+ +

Account deletion

+

PorfolioJournal does not require an account. If an account system is introduced later, we will provide an in-app option to delete your account and associated data here.

+ +

Need help?

+

If you need assistance, contact support@portfoliojournal.app.

+
+
+
+
+ + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..7bdc43e --- /dev/null +++ b/index.html @@ -0,0 +1,375 @@ + + + + + + PorfolioJournal — Calm portfolio journaling for iOS + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+ + Offline-first portfolio journaling +
+

Build a calm portfolio habit with PorfolioJournal.

+

A focused iOS app for monthly portfolio check-ins, reflection notes, and long-term clarity. Stay present, track growth, and build a record of your financial decisions without noise.

+ +
+
+
+ +
+
+
+

Portfolio clarity, without the noise

+

Everything PorfolioJournal does is built around gentle monthly updates and a durable record of your progress.

+
+
+
+ +

Monthly check-ins

+

Log updates once a month with mood, rating, notes, and progress streaks built in.

+
+
+ +

Sources-based tracking

+

Track sources, snapshots, and category tags to keep allocations readable at a glance.

+
+
+ +

Home dashboard

+

See total value, evolution, category mix, cashflow vs growth, and returns in one view.

+
+
+ +

Goals tracking

+

Set targets with pace status, ETA, and shareable goal cards to stay motivated.

+
+
+ +

Import & export

+

Move data in or out with CSV/JSON for long-term continuity and peace of mind.

+
+
+
Premium
+ +

Advanced analytics

+

Allocation, risk/return, drawdown, volatility, cashflow, and 12‑month forecasting.

+
+
+
+
+ +
+
+
+

Designed for calm focus

+

Every screen is built to reduce noise and help you reflect on what matters most.

+
+
+ +
+ +
+
+
+

Built for iOS, built for privacy

+

PorfolioJournal keeps your data on-device by default, with optional iCloud sync when you choose it.

+
+
+
+ +

Offline-first

+

Full portfolio history stays on your device, even when you are off the grid.

+
+
+ +

iCloud sync

+

Opt-in sync keeps data consistent across devices when you enable it.

+
+
+ +

Face ID ready

+

Use device-level protections and optional passcode locks for peace of mind.

+
+
+ +

Widgets

+

Track your total value at a glance with iOS widgets.

+
+
+
+
+ +
+
+
+

Trusted by calm investors

+

Replace these with real reviews once you launch.

+
+
+
+ +

“Finally, a portfolio app that feels like a journal. The monthly cadence keeps me grounded.”

+

— Placeholder Investor

+
+
+ +

“Offline-first is a game changer. I can keep sensitive notes without worrying about servers.”

+

— Placeholder Reviewer

+
+
+ +

“The goals and snapshots make it easy to explain my progress over time.”

+

— Placeholder Client

+
+
+
+
+ +
+
+
+

Questions, answered

+

Clear answers for iOS users who care about privacy and long-term tracking.

+
+
+
+ +
+
Yes. All portfolio data and journal entries are stored locally by default, so you can update anywhere.
+
+
+
+ +
+
No. iCloud is optional. Enable it only if you want to sync across devices.
+
+
+
+ +
+
Yes. Export CSV or JSON anytime for backup or migration.
+
+
+
+ +
+
No analytics or tracking is enabled by default. If analytics are added later, you will be notified.
+
+
+
+
+
+ +
+
+
+

Start your calm portfolio habit

+

Download PorfolioJournal and build a record of your investing journey that you will actually want to revisit.

+ +
+
+
+
+ + + + diff --git a/press-kit.html b/press-kit.html new file mode 100644 index 0000000..e780100 --- /dev/null +++ b/press-kit.html @@ -0,0 +1,202 @@ + + + + + + Press Kit — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+

App description

+

PorfolioJournal is an offline-first iOS app that helps investors build a long-term portfolio record through calm monthly check-ins, reflection notes, and clear allocation snapshots. It combines a focused journal with lightweight analytics, so users can track growth without the noise of day-to-day market swings.

+ +

Download assets

+
+
+ +

App icon

+

SVG placeholder for media kits and previews.

+ Download SVG +
+
+ +

Screenshots

+

Replace with actual iOS screenshots when available.

+ Download sample +
+
+ +

App icons

+
+
+ PorfolioJournal app icon + App Icon (SVG) +
+
+ PorfolioJournal favicon + Favicon (SVG) +
+
+ +

Screenshots

+
+
+ Screenshot placeholder 1 + Dashboard +
+
+ Screenshot placeholder 2 + Monthly check-in +
+
+ Screenshot placeholder 3 + Goals +
+
+ Screenshot placeholder 4 + Analytics +
+
+ +

Brand guidelines

+

Use clean typography, generous spacing, and calm gradients. Avoid clutter. The product should feel deliberate and trustworthy.

+ +
+
#667EEA
+
#764BA2
+
#0071E3
+
#34C759
+
+ +

Press contact

+

For media inquiries, reach us at press@portfoliojournal.app.

+
+
+
+
+ + + + diff --git a/privacy.html b/privacy.html new file mode 100644 index 0000000..b9cfa24 --- /dev/null +++ b/privacy.html @@ -0,0 +1,179 @@ + + + + + + Privacy Policy — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+

Privacy summary

+
    +
  • Your portfolio data and journal notes stay on your device by default.
  • +
  • iCloud sync is optional and only enabled by you.
  • +
  • No advertising trackers, and no data sold or shared.
  • +
  • Exports are initiated by you and saved where you choose.
  • +
  • Deletion is instant inside the app, with additional steps for iCloud.
  • +
+
+ +

What data we collect

+

PorfolioJournal collects the data you choose to enter into the app, such as portfolio sources, snapshots, contributions, categories, goals, and journal notes. This information is stored locally on your device unless you enable iCloud sync or export your data.

+ +

How we use your data

+

Your data is used solely to provide app functionality: portfolio calculations, charts, progress tracking, and reminders. We do not use your data for advertising or profiling.

+ +

Data storage and sync

+

By default, all content is stored on-device. If you enable iCloud sync, your data is stored in your iCloud account and synced across devices signed in with the same Apple ID. PorfolioJournal does not operate separate servers for user data.

+ +

Exports

+

You can export your data in CSV or JSON format at any time. Exported files are stored wherever you choose (Files app, local storage, or another provider you control).

+ +

Third-party services

+

PorfolioJournal does not use third-party analytics or advertising services by default.

+
+

Placeholder: If you later enable analytics or external services, list them here with links to their privacy policies and the exact data shared.

+
+ +

Data retention

+

Your data is retained on your device until you delete it. If you enable iCloud, data is retained in your iCloud account until you delete it from the app or remove it in iCloud settings.

+ +

Deleting your data

+

You can delete your portfolio data at any time from within the app. For iCloud data removal, follow the steps on the Delete Data page.

+ +

Children's privacy

+

PorfolioJournal is not directed to children under 13 and does not knowingly collect personal data from children.

+ +

Contact

+

If you have any questions about this policy or a data deletion request, contact us at support@portfoliojournal.app.

+
+
+
+
+ + + + diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..42629e4 --- /dev/null +++ b/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://portfoliojournal.app/sitemap.xml diff --git a/security.html b/security.html new file mode 100644 index 0000000..5a4335b --- /dev/null +++ b/security.html @@ -0,0 +1,157 @@ + + + + + + Security — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+

On-device storage

+

All portfolio data and journal notes are stored locally on your device by default. This keeps sensitive information off external servers.

+ +

Optional passcode and Face ID

+

PorfolioJournal can use iOS security features, including device passcodes and Face ID, to keep your data protected from unauthorized access.

+ +

iCloud sync

+

If you enable iCloud sync, your data is stored and synced through your Apple ID. iCloud uses Apple-managed encryption in transit and at rest.

+ +

Backups and exports

+

You can export CSV or JSON files for manual backups. We recommend storing backups in a trusted location and keeping your Files app secured.

+ +

Best practices

+
    +
  • Use a strong device passcode and Face ID.
  • +
  • Keep iOS and PorfolioJournal updated.
  • +
  • Protect your Apple ID with two-factor authentication.
  • +
  • Do not share your Apple ID credentials with others.
  • +
+ +

Responsible disclosure

+

If you discover a security issue, contact us at security@portfoliojournal.app. We appreciate responsible disclosure and will respond promptly.

+
+
+
+
+ + + + diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..1719003 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,43 @@ + + + + https://portfoliojournal.app/ + 2025-01-15 + + + https://portfoliojournal.app/privacy.html + 2025-01-15 + + + https://portfoliojournal.app/terms.html + 2025-01-15 + + + https://portfoliojournal.app/support.html + 2025-01-15 + + + https://portfoliojournal.app/security.html + 2025-01-15 + + + https://portfoliojournal.app/press-kit.html + 2025-01-15 + + + https://portfoliojournal.app/status.html + 2025-01-15 + + + https://portfoliojournal.app/changelog.html + 2025-01-15 + + + https://portfoliojournal.app/delete-data.html + 2025-01-15 + + + https://portfoliojournal.app/about.html + 2025-01-15 + + diff --git a/status.html b/status.html new file mode 100644 index 0000000..3787d0c --- /dev/null +++ b/status.html @@ -0,0 +1,157 @@ + + + + + + Status — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + All systems operational +
+ +
+
+ App Store downloads + Operational +
+
+ iCloud sync (optional) + Operational +
+
+ Website + Operational +
+
+ +

Past incidents

+

No incidents reported yet. Add updates here as needed.

+
+
+
+
+ + + + diff --git a/support.html b/support.html new file mode 100644 index 0000000..e83e5a7 --- /dev/null +++ b/support.html @@ -0,0 +1,191 @@ + + + + + + Support — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+
+ +

Email support

+

Send a direct message to the support team. We reply within 2 business days.

+ Email support +
+
+ +

Report a bug

+

Use the template below to share steps, device model, and iOS version.

+ Report a bug +
+
+ +

FAQ

+
+
+ +
+
Enable iCloud in Settings inside the app. Data is synced through your Apple ID and stays in your private iCloud storage.
+
+
+
+ +
+
Use Export to save CSV or JSON files to Files, iCloud Drive, or another provider you trust.
+
+
+
+ +
+
If PorfolioJournal offers paid features, use “Restore Purchases” in the app or in your App Store account settings.
+
+
+
+ +
+
If PorfolioJournal offers paid features, the core experience remains available with the base version. Premium unlocks advanced analytics and multiple accounts.
+
+
+
+ +
+
Export CSV files and share them directly with your reporting tools. You stay in control of where the files go.
+
+
+
+ +
+

Need immediate help? Email support@portfoliojournal.app and include your device model and iOS version.

+
+
+
+
+
+ + + + diff --git a/terms.html b/terms.html new file mode 100644 index 0000000..8dfaf1a --- /dev/null +++ b/terms.html @@ -0,0 +1,164 @@ + + + + + + Terms of Service — PorfolioJournal + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+

Acceptance of terms

+

By using PorfolioJournal, you agree to these Terms of Service. If you do not agree, do not use the app.

+ +

Use of the app

+

PorfolioJournal provides tools for personal portfolio tracking and journaling. You are responsible for the accuracy of the information you enter and for safeguarding your device.

+ +

Not financial advice

+

PorfolioJournal is provided for informational and organizational purposes only. It does not provide investment advice, brokerage services, or recommendations.

+ +

Subscriptions and paid features

+

If PorfolioJournal offers paid features, prices and terms will be shown in the App Store. Subscriptions are managed by Apple and can be cancelled in your Apple ID settings.

+ +

iCloud and device storage

+

Content is stored locally unless you enable iCloud sync. You are responsible for managing your iCloud settings and device backups.

+ +

Intellectual property

+

PorfolioJournal and its content are owned by PorfolioJournal or its licensors. You may not copy, modify, or distribute the app except as permitted by Apple.

+ +

Service availability

+

We work to keep the app reliable but do not guarantee uninterrupted access or error-free operation. Features may change or be discontinued with reasonable notice.

+ +

Limitation of liability

+

To the fullest extent permitted by law, PorfolioJournal is not liable for indirect or consequential damages related to your use of the app.

+ +

Contact

+

If you have questions about these terms, contact us at support@portfoliojournal.app.

+
+
+
+
+ + + +