# Glassmorphism + Liquid Glass Design System — Telegram Web App v2

## Filosofi Visual

Desain ini menggabungkan dua bahasa visual:
- **Glassmorphism** — kaca buram berlapis yang mengapung di atas gradien
- **Liquid Glass** — navbar yang hidup seperti cairan: mengembung, meregang, dan bergetar saat disentuh

Tidak ada warna tetap dalam sistem ini. Semua identitas visual datang dari **blur, transparansi, morfologi bentuk, dan cahaya pantulan**.

---

## Prinsip Utama

### 1. Transparansi Berlapis (Layered Transparency)
Setiap elemen UI menggunakan `background: rgba()` dengan alpha rendah (0.08–0.25). Kedalaman lahir dari **tumpukan lapisan**, bukan dari warna solid.

### 2. Blur sebagai Materi
`backdrop-filter: blur()` bukan hiasan — ini adalah bahan baku utama.
- **8px** → elemen minor (chat item hover)
- **16px** → elemen sedang (panel, bubble)
- **24–32px** → elemen utama (navbar, sidebar)
- **40px+** → kondisi liquid/morph aktif

### 3. Border Cahaya (Light Border)
Batas elemen adalah **cahaya tipis**, bukan garis:
```
border: 1px solid rgba(255, 255, 255, 0.18)
```
Saat morph aktif, border menjadi lebih terang (`0.32`) untuk mensimulasikan refraksi cahaya.

### 4. Bayangan Lembut (Soft Shadow)
Tidak pernah menggunakan hitam pekat. Gunakan ambient:
```
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18)
```

---

## Komponen

### Navbar Liquid Glass Tube

Ini adalah komponen inti sistem ini. Navbar berbentuk kapsul yang:
- **Bisa di-drag** ke mana saja di layar
- **Mengembung (morph)** saat ditekan/digeser — menggunakan SVG filter `feTurbulence` + `feDisplacementMap` atau `border-radius` animasi
- **Bergetar seperti cairan** saat dilepas — spring physics dengan `cubic-bezier` ekstrem
- **Zoom dock** — item yang dihover membesar, item tetangga ikut

#### Struktur Dasar

```css
.navbar-tube {
  border-radius: 9999px;
  padding: 10px 20px;

  /* Liquid Glass Base */
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(28px) saturate(200%) brightness(1.05);
  -webkit-backdrop-filter: blur(28px) saturate(200%) brightness(1.05);

  /* Border cahaya */
  border: 1px solid rgba(255, 255, 255, 0.22);

  /* Shadow dalam & luar */
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.22),
    inset 0 1.5px 0 rgba(255, 255, 255, 0.28),
    inset 0 -1px 0 rgba(0, 0, 0, 0.12),
    inset 1px 0 0 rgba(255, 255, 255, 0.08),
    inset -1px 0 0 rgba(255, 255, 255, 0.08);

  position: fixed;
  cursor: grab;
  user-select: none;
  touch-action: none;

  /* Spring transition untuk release */
  transition:
    border-radius 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow 0.3s ease,
    background 0.2s ease;
}
```

#### State: Saat Ditekan (Press)

Saat `mousedown` / `touchstart`, navbar mulai berubah bentuk — ujung-ujungnya sedikit mengembang, blur meningkat:

```css
.navbar-tube.pressing {
  /* Ujung membulat lebih agresif = efek mengembung */
  border-radius: 32px;
  padding: 13px 22px;

  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(36px) saturate(220%) brightness(1.08);

  box-shadow:
    0 12px 40px rgba(0, 0, 0, 0.28),
    inset 0 2px 0 rgba(255, 255, 255, 0.35),
    inset 0 -1px 0 rgba(0, 0, 0, 0.15);

  border-color: rgba(255, 255, 255, 0.32);

  transform: scale(1.04);
  transition: none; /* responsif saat drag */
}
```

#### State: Saat Di-drag (Dragging)

Navbar mengikuti gerakan mouse/sentuhan. Efek morph dinamis berdasarkan **kecepatan gerak**:

```css
.navbar-tube.dragging {
  cursor: grabbing;

  /* Ujung semakin membulat = lebih "cair" */
  border-radius: 28px;

  background: rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(40px) saturate(240%) brightness(1.10);

  box-shadow:
    0 20px 60px rgba(0, 0, 0, 0.35),
    0 4px 16px rgba(0, 0, 0, 0.20),
    inset 0 2px 0 rgba(255, 255, 255, 0.40),
    inset 0 -1.5px 0 rgba(0, 0, 0, 0.18);

  border-color: rgba(255, 255, 255, 0.38);

  /* Tilt berdasarkan arah gerak (via JS) */
  /* transform: rotate(-2deg) scale(1.05); — dikontrol JS */
}
```

#### State: Morph Dinamis via JS (Velocity-based)

```js
// Hitung kecepatan gerak (velocity)
const vx = currentX - prevX;  // delta posisi per frame
const vy = currentY - prevY;

// Kecepatan → intensitas morph
const speed = Math.sqrt(vx * vx + vy * vy);
const morphAmount = Math.min(speed * 0.8, 20); // max 20px

// Terapkan border-radius asimetris = efek cairan meregang
const baseR = 9999;
const stretchR = Math.max(baseR - morphAmount * 40, 18);

// Arah gerak menentukan sisi mana yang "tertarik"
if (Math.abs(vx) > Math.abs(vy)) {
  // Gerakan horizontal: kiri-kanan meregang
  navbar.style.borderRadius = `${baseR}px ${stretchR}px ${stretchR}px ${baseR}px`;
  navbar.style.transform = `rotate(${vx * 0.15}deg) scale(${1 + speed * 0.003})`;
} else {
  // Gerakan vertikal: atas-bawah mengembung
  navbar.style.borderRadius = `${stretchR}px ${stretchR}px ${baseR}px ${baseR}px`;
}

// Tilt lembut mengikuti arah
navbar.style.transform += ` perspective(600px) rotateX(${vy * -0.2}deg) rotateY(${vx * 0.2}deg)`;
```

#### State: Release (Spring Back)

Saat dilepas, navbar "memantul" kembali ke bentuk kapsul sempurna:

```css
.navbar-tube.releasing {
  border-radius: 9999px;
  transform: scale(1) rotate(0deg);
  backdrop-filter: blur(28px) saturate(200%);

  /* Spring bounce — overshoot dan balik */
  transition:
    border-radius 0.55s cubic-bezier(0.34, 1.56, 0.64, 1),
    transform 0.55s cubic-bezier(0.34, 1.56, 0.64, 1),
    backdrop-filter 0.4s ease,
    box-shadow 0.4s ease;
}
```

#### Double-click: Reset Posisi

```js
// Double click → animasi terbang ke posisi default (bottom center)
navbar.addEventListener('dblclick', () => {
  navbar.classList.add('snapping');
  // posisi: bottom: 24px, left: 50% - width/2
});
```

```css
.navbar-tube.snapping {
  transition:
    left 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
    top 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
    border-radius 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
```

---

### Zoom Dock Effect (Nav Item)

Saat hover, item membesar dengan spring bounce. Item tetangga ikut bergerak secara proporsional (macOS Dock style):

```js
// Hitung "magnet" berdasarkan jarak ke cursor
items.forEach((item, i) => {
  const dist = Math.abs(i - hoveredIndex);
  const scales = [1.42, 1.22, 1.08, 1.0]; // dist 0, 1, 2, 3+
  const scale = scales[Math.min(dist, 3)];
  const lift  = [6, 3, 1, 0][Math.min(dist, 3)]; // px naik
  item.style.transform = `scale(${scale}) translateY(-${lift}px)`;
});
```

```css
.nav-item {
  transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
}
```

---

### SVG Liquid Filter (Opsional — Advanced)

Untuk efek cairan yang lebih organik, terapkan SVG filter langsung di atas navbar:

```html
<svg style="position:absolute;width:0;height:0">
  <defs>
    <filter id="liquid">
      <feTurbulence
        type="fractalNoise"
        baseFrequency="0.015"
        numOctaves="2"
        seed="2"
        result="noise"
      />
      <feDisplacementMap
        in="SourceGraphic"
        in2="noise"
        scale="0"        <!-- scale di-animasikan via JS saat drag: 0→18 -->
        xChannelSelector="R"
        yChannelSelector="G"
      />
    </filter>
  </defs>
</svg>
```

```js
// Saat dragging: naikkan scale displacement sesuai kecepatan
displacementMap.setAttribute('scale', Math.min(speed * 1.5, 18));

// Saat release: turunkan kembali ke 0
displacementMap.setAttribute('scale', 0);
```

---

### Button Glass

```css
.btn-glass {
  background: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.20);
  border-radius: 14px;
  box-shadow:
    0 4px 16px rgba(0, 0, 0, 0.12),
    inset 0 1px 0 rgba(255, 255, 255, 0.22);
  transition: all 0.22s cubic-bezier(0.4, 0, 0.2, 1);
}

.btn-glass:hover {
  background: rgba(255, 255, 255, 0.20);
  border-color: rgba(255, 255, 255, 0.30);
  transform: translateY(-1px);
  box-shadow:
    0 8px 24px rgba(0, 0, 0, 0.18),
    inset 0 1px 0 rgba(255, 255, 255, 0.30);
}

.btn-glass:active {
  background: rgba(255, 255, 255, 0.08);
  transform: scale(0.97);
}
```

---

### Panel & Card

```css
.panel-glass {
  background: rgba(255, 255, 255, 0.07);
  backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 20px;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.14);
}

.chat-card {
  background: rgba(255, 255, 255, 0.055);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 16px;
  transition: background 0.18s ease, transform 0.18s ease;
}

.chat-card:hover {
  background: rgba(255, 255, 255, 0.11);
  border-color: rgba(255, 255, 255, 0.15);
  transform: translateX(4px);
}
```

---

### Input & Message Bubble

```css
.input-glass {
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 22px;
  transition: border-color 0.2s, background 0.2s;
}
.input-glass:focus-within {
  background: rgba(255, 255, 255, 0.13);
  border-color: rgba(255, 255, 255, 0.30);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.07);
}

.bubble-incoming {
  background: rgba(255, 255, 255, 0.09);
  backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 18px 18px 18px 4px;
}

.bubble-outgoing {
  background: rgba(255, 255, 255, 0.19);
  backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 18px 18px 4px 18px;
}
```

---

## Urutan State Morph Navbar

```
IDLE          → kapsul penuh, blur 28px, radius 9999px
     ↓ press
PRESSING      → mengembung, border-radius 32px, scale 1.04, blur 36px
     ↓ gerak
DRAGGING      → cairan meregang, radius asimetris, tilt sesuai arah, blur 40px
     ↓ lepas
RELEASING     → spring bounce, kembali ke 9999px dengan overshoot
     ↓ diam
IDLE
```

---

## Tipografi

- **Header / Nama:** `SF Pro Display` → `Inter`, weight 700, tracking -0.02em
- **Body / Pesan:** `SF Pro Text` → `Inter`, weight 400, line-height 1.55
- **Timestamp:** 11px, opacity 0.45
- Semua teks: putih/terang (opacity 0.85–1.0)

---

## Background

Background kaya warna diperlukan agar efek kaca terlihat. Gunakan:
- Gradient mesh 2–3 warna bersudut acak
- Atau gambar bokeh/abstrak sebagai base layer
- Tambahkan `background-attachment: fixed` agar paralaks saat scroll

---

## Aksesibilitas

```css
@media (prefers-reduced-motion: reduce) {
  .navbar-tube { transition: none !important; }
  .nav-item    { transition: none !important; }
}
```
- Kontras teks minimum 4.5:1
- Focus ring: `outline: 2px solid rgba(255,255,255,0.6)`
- Keyboard nav untuk item navbar tetap berfungsi

---

## Checklist Implementasi

- [ ] Semua background elemen pakai `rgba()`, tidak ada solid
- [ ] `backdrop-filter: blur()` di setiap komponen
- [ ] Border pakai `rgba(255,255,255, 0.1–0.32)`
- [ ] Navbar: morph saat press (border-radius mengembung)
- [ ] Navbar: morph asimetris saat drag (border-radius berbeda tiap sisi)
- [ ] Navbar: tilt + scale berdasarkan velocity gerak
- [ ] Navbar: spring release dengan cubic-bezier bounce
- [ ] Navbar: zoom dock effect pada hover item
- [ ] SVG liquid filter opsional terpasang
- [ ] Double-click navbar → snap ke posisi default
- [ ] `prefers-reduced-motion` direspek
