body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
}
.calc-container {
max-width: 900px;
margin: 20px auto;
padding: 20px;
}
/* ── Header ── */
.calc-header {
margin-bottom: 30px;
padding: 25px;
background: linear-gradient(135deg, #2196F3 0%, #1976D2 100%);
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
color: white;
}
.calc-header h2 {
margin-top: 0;
color: white;
font-size: 28px;
margin-bottom: 10px;
}
.calc-header p {
margin: 10px 0 20px 0;
opacity: 0.95;
font-size: 15px;
}
/* ── Form controls inside header ── */
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
margin-top: 20px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.form-group label {
font-weight: 600;
font-size: 14px;
color: white;
}
.form-group input,
.form-group select {
padding: 12px;
font-size: 15px;
border: 2px solid rgba(255,255,255,0.3);
border-radius: 6px;
background: rgba(255,255,255,0.95);
transition: all 0.3s ease;
font-family: 'Courier New', monospace;
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: #4CAF50;
background: white;
box-shadow: 0 0 0 3px rgba(76,175,80,0.15);
}
.form-group select {
cursor: pointer;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* ── Buttons ── */
.btn {
padding: 12px 24px;
font-size: 15px;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.btn-primary {
background: #4CAF50;
color: white;
}
.btn-primary:hover {
background: #45a049;
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.25);
}
.btn-primary:active {
background: #3d8b40;
transform: translateY(0);
}
.btn-secondary {
background: rgba(255,255,255,0.2);
color: white;
border: 2px solid rgba(255,255,255,0.4);
}
.btn-secondary:hover {
background: rgba(255,255,255,0.3);
transform: translateY(-1px);
}
.btn-danger {
background: #f44336;
color: white;
}
.btn-danger:hover {
background: #d32f2f;
transform: translateY(-1px);
}
.btn-sm {
padding: 6px 14px;
font-size: 13px;
}
.submit-btn {
padding: 14px 35px;
font-size: 16px;
background: #4CAF50;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
margin-top: 15px;
width: 100%;
}
.submit-btn:hover {
background: #45a049;
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}
.submit-btn:active {
background: #3d8b40;
transform: translateY(0);
}
/* ── Result sections ── */
.result-section {
background: white;
border: 1px solid #e0e0e0;
border-radius: 8px;
margin-top: 20px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
transition: all 0.3s ease;
display: none;
}
.result-section.show {
display: block;
}
.result-section:hover {
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.section-header {
background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%);
color: white;
padding: 15px 20px;
}
.section-header h3 {
margin: 0;
font-size: 18px;
display: flex;
align-items: center;
gap: 10px;
}
.section-header.blue {
background: linear-gradient(135deg, #2196F3 0%, #1976D2 100%);
}
.section-header.orange {
background: linear-gradient(135deg, #FF9800 0%, #F57C00 100%);
}
.section-header.purple {
background: linear-gradient(135deg, #9C27B0 0%, #7B1FA2 100%);
}
.section-content {
padding: 20px;
background: #fafafa;
}
.data-row {
display: flex;
margin: 10px 0;
padding: 10px;
background: white;
border-radius: 4px;
border-left: 3px solid #4CAF50;
align-items: flex-start;
}
.data-label {
font-weight: bold;
color: #555;
min-width: 200px;
flex-shrink: 0;
font-size: 14px;
padding-top: 1px;
}
.data-value {
color: #333;
font-family: 'Courier New', monospace;
word-break: break-word;
font-size: 15px;
}
.data-value.highlight {
color: #1976D2;
font-weight: bold;
font-size: 18px;
}
/* ── Help text ── */
.help-text {
margin-top: 15px;
font-size: 14px;
color: rgba(255,255,255,0.9);
background: rgba(0,0,0,0.1);
padding: 10px 15px;
border-radius: 4px;
}
.help-text strong {
color: white;
}
/* ── Topology canvas area ── */
#cy-container {
width: 100%;
height: 380px;
background: #1a2332;
border-radius: 8px;
border: 2px solid #2d3d52;
position: relative;
overflow: hidden;
}
#cy {
width: 100%;
height: 100%;
}
/* ── Switch list ── */
.switch-list,
.link-list {
list-style: none;
margin: 0;
padding: 0;
}
.switch-item,
.link-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
background: white;
border-radius: 5px;
margin-bottom: 6px;
border-left: 4px solid #2196F3;
font-size: 14px;
flex-wrap: wrap;
}
.switch-item .sw-id {
font-family: 'Courier New', monospace;
font-weight: bold;
color: #1976D2;
min-width: 40px;
}
.switch-item .sw-name {
flex: 1;
font-weight: 600;
}
.switch-item .sw-priority,
.switch-item .sw-mac {
font-family: 'Courier New', monospace;
font-size: 13px;
color: #666;
}
.link-item {
border-left-color: #FF9800;
}
.link-item .lk-label {
flex: 1;
font-family: 'Courier New', monospace;
font-size: 13px;
}
.tag {
display: inline-block;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.tag-root { background: #FFF3CD; color: #856404; }
.tag-fwd { background: #D4EDDA; color: #155724; }
.tag-blk { background: #F8D7DA; color: #721C24; }
.tag-disc { background: #D1ECF1; color: #0C5460; }
.tag-lrn { background: #CCE5FF; color: #004085; }
.tag-edge { background: #E2D9F3; color: #491F8A; }
/* ── Port state table ── */
.port-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
margin-top: 8px;
}
.port-table th {
background: #E3F2FD;
color: #1565C0;
padding: 8px 12px;
text-align: left;
font-weight: 600;
border-bottom: 2px solid #BBDEFB;
}
.port-table td {
padding: 7px 12px;
border-bottom: 1px solid #f0f0f0;
font-family: 'Courier New', monospace;
font-size: 13px;
}
.port-table tr:last-child td {
border-bottom: none;
}
.port-table tr:nth-child(even) td {
background: #f8f9fa;
}
/* ── Timeline ── */
.timeline {
position: relative;
padding-left: 28px;
}
.timeline::before {
content: '';
position: absolute;
left: 8px;
top: 0;
bottom: 0;
width: 2px;
background: #BBDEFB;
}
.timeline-event {
position: relative;
margin-bottom: 12px;
background: white;
border-radius: 6px;
padding: 10px 14px;
border: 1px solid #e8e8e8;
font-size: 13px;
}
.timeline-event::before {
content: '';
position: absolute;
left: -24px;
top: 12px;
width: 10px;
height: 10px;
border-radius: 50%;
background: #2196F3;
border: 2px solid white;
box-shadow: 0 0 0 2px #2196F3;
}
.timeline-event.root-election::before { background: #FFC107; box-shadow: 0 0 0 2px #FFC107; }
.timeline-event.port-change::before { background: #4CAF50; box-shadow: 0 0 0 2px #4CAF50; }
.timeline-event.port-blocked::before { background: #f44336; box-shadow: 0 0 0 2px #f44336; }
.timeline-event.convergence::before { background: #9C27B0; box-shadow: 0 0 0 2px #9C27B0; }
.timeline-event .te-time {
font-weight: bold;
color: #1976D2;
font-family: 'Courier New', monospace;
margin-right: 8px;
}
.timeline-event .te-desc {
color: #333;
}
/* ── BPDU Inspector ── */
.bpdu-panel {
background: #0d1117;
border-radius: 6px;
padding: 15px;
font-family: 'Courier New', monospace;
font-size: 13px;
color: #79c0ff;
max-height: 300px;
overflow-y: auto;
}
.bpdu-row {
display: flex;
gap: 8px;
margin-bottom: 3px;
line-height: 1.5;
}
.bpdu-field {
color: #d2a8ff;
min-width: 180px;
flex-shrink: 0;
}
.bpdu-val {
color: #a5f3fc;
}
.bpdu-val.root { color: #fbbf24; }
.bpdu-val.bridge { color: #86efac; }
/* ── Scenario selector ── */
.scenario-bar {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
margin-top: 10px;
}
.scenario-bar label {
font-weight: 600;
font-size: 14px;
color: white;
}
.scenario-bar select {
padding: 8px 12px;
border: 2px solid rgba(255,255,255,0.3);
border-radius: 6px;
background: rgba(255,255,255,0.95);
font-size: 14px;
cursor: pointer;
flex: 1;
min-width: 200px;
}
/* ── Legend ── */
.legend {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 8px;
font-size: 13px;
}
.legend-item {
display: flex;
align-items: center;
gap: 5px;
}
.legend-dot {
width: 12px;
height: 12px;
border-radius: 50%;
flex-shrink: 0;
}
/* ── Inline error / info messages ── */
.msg {
padding: 10px 14px;
border-radius: 6px;
font-size: 14px;
margin-top: 8px;
}
.msg-error {
background: #FFEBEE;
color: #C62828;
border-left: 4px solid #f44336;
}
.msg-info {
background: #E3F2FD;
color: #1565C0;
border-left: 4px solid #2196F3;
}
.msg-success {
background: #E8F5E9;
color: #1B5E20;
border-left: 4px solid #4CAF50;
}
/* ── STP concept panel ── */
.concept-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.concept-card {
background: white;
border-radius: 6px;
padding: 14px;
border-top: 3px solid #2196F3;
font-size: 13px;
}
.concept-card h4 {
margin: 0 0 6px 0;
color: #1976D2;
font-size: 14px;
}
.concept-card p {
margin: 0;
color: #555;
line-height: 1.5;
}
.concept-card.rstp {
border-top-color: #9C27B0;
}
.concept-card.rstp h4 {
color: #7B1FA2;
}
/* ── Mode toggle ── */
.mode-toggle {
display: flex;
gap: 0;
margin-top: 15px;
background: rgba(0,0,0,0.15);
border-radius: 6px;
padding: 4px;
}
.mode-btn {
flex: 1;
padding: 8px 16px;
border: none;
background: transparent;
color: rgba(255,255,255,0.7);
cursor: pointer;
border-radius: 4px;
font-size: 14px;
font-weight: 600;
transition: all 0.2s ease;
}
.mode-btn.active {
background: white;
color: #1976D2;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
/* ── Pulse animation for root bridge ── */
@keyframes rootPulse {
0% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(255, 193, 7, 0); }
100% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); }
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in-up {
animation: fadeInUp 0.35s ease both;
}
/* ── Responsive ── */
@media (max-width: 768px) {
.form-grid {
grid-template-columns: 1fr;
}
.data-row {
flex-direction: column;
}
.data-label {
margin-bottom: 4px;
min-width: auto;
}
.concept-grid {
grid-template-columns: 1fr;
}
#cy-container {
height: 280px;
}
.port-table {
font-size: 12px;
}
.port-table th,
.port-table td {
padding: 6px 8px;
}
.mode-btn {
padding: 8px 8px;
font-size: 13px;
}
.scenario-bar {
flex-direction: column;
align-items: stretch;
}
.scenario-bar label {
display: block;
}
}
@media (max-width: 480px) {
.calc-header {
padding: 18px;
}
.calc-header h2 {
font-size: 22px;
}
.switch-item,
.link-item {
flex-wrap: wrap;
}
}
═════════════════════════════ ══════════════════════════════
BAŞLIK / YAPILANDIRMA
═════════════════════════════ ══════════════════════════════
/.calc-başlığı
═════════════════════════════ ══════════════════════════════
GÜNCEL TOPOLOJİ LİSTESİ
═════════════════════════════ ══════════════════════════════
Bağlantılar
- Henüz bağlantı eklenmedi.
═════════════════════════════ ══════════════════════════════
TOPOLOJİ GÖRSELLEŞTİRME
═════════════════════════════ ══════════════════════════════
Efsane
Yönlendirme Bağlantı Noktası
Bağlantı Noktasını Engelleme / Atma
Belirlenmiş Bağlantı Noktası
Kesikli çizgi = engellenen bağlantı
═════════════════════════════ ══════════════════════════════
KÖPRÜ SEÇİMİ
═════════════════════════════ ══════════════════════════════
═════════════════════════════ ══════════════════════════════
LİMAN DEVLETLERİ
═════════════════════════════ ══════════════════════════════
═════════════════════════════ ══════════════════════════════
BPDU MÜFETTİŞİ
═════════════════════════════ ══════════════════════════════
═════════════════════════════ ══════════════════════════════
YAKINSAŞMA ZAMAN ÇİZELGİSİ
═════════════════════════════ ══════════════════════════════
═════════════════════════════ ══════════════════════════════
STP KAVRAMLARI
═════════════════════════════ ══════════════════════════════
Kök Köprü Seçimi
En düşük Köprü Kimliğine sahip anahtar kazanır. Köprü Kimliği = Öncelik (varsayılan 32768) + MAC adresi. Öncelikli bağlar sayısal olarak daha düşük MAC'a gider. VLAN başına yalnızca bir temel köprü.
Kök Bağlantı Noktası
Kök olmayan her anahtar, temel köprüye giden en düşük kümülatif yol maliyetine sahip bağlantı noktası olan bir Kök Bağlantı Noktasını seçer. Bağlantılar komşu Köprü Kimliği ve ardından bağlantı noktası kimliği ile kopar.
Belirlenmiş Bağlantı Noktası
Her ağ kesiminin tam olarak bir Atanmış Bağlantı Noktası vardır; bu, köke giden en iyi (en düşük maliyetli) yolu sunan bağlantı noktasıdır. Temel köprüdeki tüm bağlantı noktaları belirlenmiştir.
Engellenen / Atılan Bağlantı Noktaları
Kök Bağlantı Noktası veya Atanmış Bağlantı Noktası olmayan herhangi bir bağlantı noktası engellenir (STP) veya atılır (RSTP). Bunlar, döngü içermeyen bir topolojiyi korurken Katman-2 döngülerini kırar.
RSTP (802.1w) Kenar Bağlantı Noktaları
RSTP uç bağlantı noktaları diğer anahtarlara değil uç ana bilgisayarlara bağlanır. STP'nin PortFast özelliğine eşdeğer olan Yönlendirme'ye (dinleme/öğrenme gecikmesi yok) anında geçiş yaparlar.
RSTP Yakınsama Hızı
STP yakınsaması 30-50 saniye sürer (bağlantı noktası başına Dinleme 15 saniye + Öğrenme 15 saniye). RSTP, atlama başına 2 saniyenin altında birleşen bir Teklif/Anlaşma anlaşması kullanır.
Yol Maliyeti (IEEE 802.1D)
10 Gbps = 2, 1 Gbps = 4, 100 Mbps = 19, 10 Mbps = 100, 1,5 Mbps = 1000. Daha düşük maliyet = tercih edilen yol. Kök köprünün maliyeti 0'dır; her atlama kendi liman maliyetini ekler.
BPDU (Köprü Protokolü Veri Birimi)
BPDU'lar şunları taşır: Kök Köprü Kimliği, Kök Yol Maliyeti, Gönderici Köprüsü Kimliği, Bağlantı Noktası Kimliği ve zamanlayıcılar. Kök köprü, her Merhaba Zamanında (2s) BPDU'ları oluşturur. Diğer köprüler bunları Belirlenmiş Bağlantı Noktalarına aktarır.
/.calc-konteyner
Cytoscape.js CDN'si