@jjlmoya/utils-drones 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/package.json +64 -63
  2. package/src/category/i18n/de.ts +106 -0
  3. package/src/category/i18n/id.ts +106 -0
  4. package/src/category/i18n/it.ts +106 -0
  5. package/src/category/i18n/ja.ts +106 -0
  6. package/src/category/i18n/ko.ts +106 -0
  7. package/src/category/i18n/nl.ts +106 -0
  8. package/src/category/i18n/pl.ts +106 -0
  9. package/src/category/i18n/pt.ts +106 -0
  10. package/src/category/i18n/ru.ts +106 -0
  11. package/src/category/i18n/sv.ts +106 -0
  12. package/src/category/i18n/tr.ts +106 -0
  13. package/src/category/i18n/zh.ts +106 -0
  14. package/src/category/index.ts +12 -0
  15. package/src/components/SecurityWarning.astro +140 -0
  16. package/src/tests/faq_count.test.ts +1 -1
  17. package/src/tests/i18n_coverage.test.ts +36 -0
  18. package/src/tests/locale_completeness.test.ts +2 -2
  19. package/src/tests/schemas_fulfillment.test.ts +23 -0
  20. package/src/tests/slug_uniqueness.test.ts +81 -0
  21. package/src/tests/title_quality.test.ts +55 -0
  22. package/src/tool/antenna-length-calculator/component.astro +70 -13
  23. package/src/tool/antenna-length-calculator/i18n/de.ts +276 -0
  24. package/src/tool/antenna-length-calculator/i18n/en.ts +76 -38
  25. package/src/tool/antenna-length-calculator/i18n/es.ts +76 -38
  26. package/src/tool/antenna-length-calculator/i18n/fr.ts +76 -38
  27. package/src/tool/antenna-length-calculator/i18n/id.ts +242 -0
  28. package/src/tool/antenna-length-calculator/i18n/it.ts +276 -0
  29. package/src/tool/antenna-length-calculator/i18n/ja.ts +276 -0
  30. package/src/tool/antenna-length-calculator/i18n/ko.ts +276 -0
  31. package/src/tool/antenna-length-calculator/i18n/nl.ts +276 -0
  32. package/src/tool/antenna-length-calculator/i18n/pl.ts +276 -0
  33. package/src/tool/antenna-length-calculator/i18n/pt.ts +276 -0
  34. package/src/tool/antenna-length-calculator/i18n/ru.ts +276 -0
  35. package/src/tool/antenna-length-calculator/i18n/sv.ts +276 -0
  36. package/src/tool/antenna-length-calculator/i18n/tr.ts +276 -0
  37. package/src/tool/antenna-length-calculator/i18n/zh.ts +276 -0
  38. package/src/tool/antenna-length-calculator/index.ts +12 -0
  39. package/src/tool/drone-flight-time/component.astro +320 -319
  40. package/src/tool/drone-flight-time/components/FlightDashboard.astro +6 -0
  41. package/src/tool/drone-flight-time/i18n/de.ts +238 -0
  42. package/src/tool/drone-flight-time/i18n/en.ts +76 -38
  43. package/src/tool/drone-flight-time/i18n/es.ts +76 -38
  44. package/src/tool/drone-flight-time/i18n/fr.ts +76 -38
  45. package/src/tool/drone-flight-time/i18n/id.ts +238 -0
  46. package/src/tool/drone-flight-time/i18n/it.ts +238 -0
  47. package/src/tool/drone-flight-time/i18n/ja.ts +239 -0
  48. package/src/tool/drone-flight-time/i18n/ko.ts +239 -0
  49. package/src/tool/drone-flight-time/i18n/nl.ts +239 -0
  50. package/src/tool/drone-flight-time/i18n/pl.ts +239 -0
  51. package/src/tool/drone-flight-time/i18n/pt.ts +239 -0
  52. package/src/tool/drone-flight-time/i18n/ru.ts +239 -0
  53. package/src/tool/drone-flight-time/i18n/sv.ts +239 -0
  54. package/src/tool/drone-flight-time/i18n/tr.ts +239 -0
  55. package/src/tool/drone-flight-time/i18n/zh.ts +239 -0
  56. package/src/tool/drone-flight-time/index.ts +12 -0
  57. package/src/tool/gps-coordinates-converter/component.astro +473 -549
  58. package/src/tool/gps-coordinates-converter/components/GpsHistory.astro +6 -1
  59. package/src/tool/gps-coordinates-converter/i18n/de.ts +222 -0
  60. package/src/tool/gps-coordinates-converter/i18n/en.ts +76 -20
  61. package/src/tool/gps-coordinates-converter/i18n/es.ts +76 -20
  62. package/src/tool/gps-coordinates-converter/i18n/fr.ts +75 -2
  63. package/src/tool/gps-coordinates-converter/i18n/id.ts +222 -0
  64. package/src/tool/gps-coordinates-converter/i18n/it.ts +222 -0
  65. package/src/tool/gps-coordinates-converter/i18n/ja.ts +222 -0
  66. package/src/tool/gps-coordinates-converter/i18n/ko.ts +222 -0
  67. package/src/tool/gps-coordinates-converter/i18n/nl.ts +222 -0
  68. package/src/tool/gps-coordinates-converter/i18n/pl.ts +222 -0
  69. package/src/tool/gps-coordinates-converter/i18n/pt.ts +222 -0
  70. package/src/tool/gps-coordinates-converter/i18n/ru.ts +222 -0
  71. package/src/tool/gps-coordinates-converter/i18n/sv.ts +222 -0
  72. package/src/tool/gps-coordinates-converter/i18n/tr.ts +222 -0
  73. package/src/tool/gps-coordinates-converter/i18n/zh.ts +222 -0
  74. package/src/tool/gps-coordinates-converter/index.ts +12 -0
@@ -30,246 +30,149 @@ const { ui } = Astro.props;
30
30
  </div>
31
31
  </div>
32
32
 
33
- <script is:inline>
34
- let mode = 'DD';
35
- let mapInstance = null;
36
- let L = null;
37
-
38
- const elements = {
39
- latDD: document.getElementById('latDD'),
40
- lngDD: document.getElementById('lngDD'),
41
- latG: document.getElementById('latG'),
42
- latM: document.getElementById('latM'),
43
- latS: document.getElementById('latS'),
44
- latH: document.getElementById('latH'),
45
- lngG: document.getElementById('lngG'),
46
- lngM: document.getElementById('lngM'),
47
- lngS: document.getElementById('lngS'),
48
- lngH: document.getElementById('lngH'),
49
- valDD: document.getElementById('valDD'),
50
- valGMS: document.getElementById('valGMS'),
51
- valDM: document.getElementById('valDM'),
52
- valMaps: document.getElementById('valMaps'),
53
- historyList: document.getElementById('historyList'),
54
- modeDD: document.getElementById('modeDD'),
55
- modeGMS: document.getElementById('modeGMS'),
56
- ddInputs: document.getElementById('dd-inputs'),
57
- gmsInputs: document.getElementById('gms-inputs'),
58
- btnMyLocation: document.getElementById('btnMyLocation'),
59
- };
60
- const container = document.querySelector('.gps-converter-ui');
61
- const uiLocal = {
62
- copied: container?.dataset.uiCopied || 'Copied',
63
- noHistory: container?.dataset.uiNoHistory || 'No history',
64
- load: container?.dataset.uiLoad || 'Load',
65
- delete: container?.dataset.uiDelete || 'Delete'
66
- };
67
-
68
- function init() {
69
- import('leaflet').then(module => {
70
- L = module.default;
71
- initMap();
72
- setupListeners();
73
- loadHistory();
74
- updateFromDD(40.4168, -3.7038);
75
- });
76
- }
77
-
78
- function initMap() {
79
- const mapContainer = document.getElementById('gpsMap');
80
- if (!mapContainer) return;
81
-
82
- mapInstance = L.map('gpsMap').setView([40.4168, -3.7038], 13);
83
- L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
84
- attribution: '© OpenStreetMap contributors',
85
- maxZoom: 19
86
- }).addTo(mapInstance);
87
-
88
- mapInstance.on('click', (e) => {
89
- updateFromDD(e.latlng.lat, e.latlng.lng);
90
- });
91
- }
33
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
34
+ <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="" is:inline></script>
92
35
 
93
- function parseCoordValue(val) {
94
- return parseFloat(val.replace(',', '.'));
95
- }
96
-
97
- function setupModeListeners() {
98
- elements.modeDD?.addEventListener('click', () => switchMode('DD'));
99
- elements.modeGMS?.addEventListener('click', () => switchMode('GMS'));
36
+ <script is:inline>
37
+ function getHemisphere(val, isLat) {
38
+ if (val >= 0) return isLat ? 'N' : 'E';
39
+ return isLat ? 'S' : 'W';
100
40
  }
101
-
102
- function setupLocationListener() {
103
- elements.btnMyLocation?.addEventListener('click', () => {
104
- if ("geolocation" in navigator) {
105
- navigator.geolocation.getCurrentPosition((position) => {
106
- updateFromDD(position.coords.latitude, position.coords.longitude);
107
- });
108
- }
109
- });
41
+ function decimalToGMS(d, isLat) {
42
+ const h = getHemisphere(d, isLat);
43
+ const absD = Math.abs(d);
44
+ const g = Math.floor(absD);
45
+ const m = Math.floor((absD - g) * 60);
46
+ const s = ((absD - g) * 60 - m) * 60;
47
+ return {g, m, s, h, mDec: (absD - g) * 60};
110
48
  }
111
-
112
- function setupDDInputListeners() {
113
- [elements.latDD, elements.lngDD].forEach(el => {
114
- el?.addEventListener('input', () => {
115
- if (mode === 'DD') {
116
- const lat = parseCoordValue(elements.latDD.value);
117
- const lng = parseCoordValue(elements.lngDD.value);
118
- updateFromDD(lat, lng, false);
119
- }
120
- });
121
- });
49
+ function formatGMS(obj) {
50
+ return `${obj.g}° ${obj.m}' ${obj.s.toFixed(2)}" ${obj.h}`;
122
51
  }
123
-
124
- function setupGMSInputListeners() {
125
- const gmsElements = [elements.latG, elements.latM, elements.latS, elements.latH,
126
- elements.lngG, elements.lngM, elements.lngS, elements.lngH];
127
- gmsElements.forEach(el => {
128
- el?.addEventListener('input', () => {
129
- if (mode === 'GMS') {
130
- const lat = gmsToDecimal(
131
- parseFloat(elements.latG.value) || 0,
132
- parseFloat(elements.latM.value) || 0,
133
- parseFloat(elements.latS.value) || 0,
134
- elements.latH.value
135
- );
136
- const lng = gmsToDecimal(
137
- parseFloat(elements.lngG.value) || 0,
138
- parseFloat(elements.lngM.value) || 0,
139
- parseFloat(elements.lngS.value) || 0,
140
- elements.lngH.value
141
- );
142
- updateFromDD(lat, lng, false);
143
- }
144
- });
145
- });
52
+ function formatDM(obj) {
53
+ return `${obj.g}° ${obj.mDec.toFixed(3)}' ${obj.h}`;
146
54
  }
147
-
148
- function setupCopyListeners() {
149
- document.querySelectorAll('.copy-btn').forEach(btn => {
150
- btn.addEventListener('click', () => {
151
- const targetId = btn.getAttribute('data-copy');
152
- const text = document.getElementById(targetId)?.textContent;
153
- if (text) {
154
- navigator.clipboard.writeText(text);
155
- const original = btn.innerHTML;
156
- btn.innerHTML = uiLocal.copied;
157
- setTimeout(() => btn.innerHTML = original, 2000);
158
- }
159
- });
160
- });
55
+ function id(name) {
56
+ return document.getElementById(name);
161
57
  }
162
-
163
- function setupClearHistoryListener() {
164
- document.getElementById('clearHistory')?.addEventListener('click', () => {
165
- localStorage.removeItem('gps_history');
166
- loadHistory();
167
- });
58
+ const state={el:{}, ui:{}, mode:'DD', map:null, L:window.L};
59
+ function initElements() {
60
+ state.el = {
61
+ latDD:id('latDD'),lngDD:id('lngDD'),latG:id('latG'),latM:id('latM'),
62
+ latS:id('latS'),latH:id('latH'),lngG:id('lngG'),lngM:id('lngM'),
63
+ lngS:id('lngS'),lngH:id('lngH'),valDD:id('valDD'),valGMS:id('valGMS'),
64
+ valDM:id('valDM'),valMaps:id('valMaps'),historyList:id('historyList'),
65
+ modeDD:id('modeDD'),modeGMS:id('modeGMS'),ddInputs:id('dd-inputs'),
66
+ gmsInputs:id('gms-inputs'),btnMyLocation:id('btnMyLocation')
67
+ };
168
68
  }
169
-
170
- function setupListeners() {
171
- setupModeListeners();
172
- setupLocationListener();
173
- setupDDInputListeners();
174
- setupGMSInputListeners();
175
- setupCopyListeners();
176
- setupClearHistoryListener();
69
+ function getUIValue(attr, def) {
70
+ const ct = document.querySelector('.gps-converter-ui');
71
+ return ct?.dataset[attr] || def;
177
72
  }
178
-
179
- function setSwitchModeDisplay(isDD) {
180
- if (isDD) {
181
- if (elements.ddInputs) elements.ddInputs.style.display = 'grid';
182
- if (elements.gmsInputs) elements.gmsInputs.style.display = 'none';
183
- } else {
184
- if (elements.ddInputs) elements.ddInputs.style.display = 'none';
185
- if (elements.gmsInputs) elements.gmsInputs.style.display = 'flex';
186
- }
73
+ function initUI() {
74
+ state.ui = {
75
+ copied: getUIValue('uiCopied', 'Copied'),
76
+ noHistory: getUIValue('uiNoHistory', 'No history'),
77
+ load: getUIValue('uiLoad', 'Load'),
78
+ delete: getUIValue('uiDelete', 'Delete')
79
+ };
187
80
  }
188
-
189
- function setSwitchModeActive(isDD) {
190
- if (isDD) {
191
- elements.modeDD?.classList.add('active');
192
- elements.modeGMS?.classList.remove('active');
193
- } else {
194
- elements.modeDD?.classList.remove('active');
195
- elements.modeGMS?.classList.add('active');
196
- }
81
+ function initState() {
82
+ initElements();
83
+ initUI();
197
84
  }
198
-
199
- function switchMode(newMode) {
200
- mode = newMode;
201
- const isDD = mode === 'DD';
202
- setSwitchModeActive(isDD);
203
- setSwitchModeDisplay(isDD);
85
+ function setLatGMS(gms) {
86
+ if (state.el.latG) state.el.latG.value = gms.g.toString();
87
+ if (state.el.latM) state.el.latM.value = gms.m.toString();
88
+ if (state.el.latS) state.el.latS.value = gms.s.toFixed(2);
89
+ if (state.el.latH) state.el.latH.value = gms.h;
204
90
  }
205
-
206
- function updateGMSInputs(lat, lng) {
207
- const latGMS = decimalToGMS(lat, true);
208
- const lngGMS = decimalToGMS(lng, false);
209
- elements.latG.value = latGMS.g.toString();
210
- elements.latM.value = latGMS.m.toString();
211
- elements.latS.value = latGMS.s.toFixed(2);
212
- elements.latH.value = latGMS.h;
213
- elements.lngG.value = lngGMS.g.toString();
214
- elements.lngM.value = lngGMS.m.toString();
215
- elements.lngS.value = lngGMS.s.toFixed(2);
216
- elements.lngH.value = lngGMS.h;
91
+ function setLngGMS(gms) {
92
+ if (state.el.lngG) state.el.lngG.value = gms.g.toString();
93
+ if (state.el.lngM) state.el.lngM.value = gms.m.toString();
94
+ if (state.el.lngS) state.el.lngS.value = gms.s.toFixed(2);
95
+ if (state.el.lngH) state.el.lngH.value = gms.h;
217
96
  }
218
-
219
- function updateResultsDisplay(lat, lng) {
220
- const latGMS = decimalToGMS(lat, true);
221
- const lngGMS = decimalToGMS(lng, false);
222
- if (elements.valDD) elements.valDD.textContent = `${lat.toFixed(6)}, ${lng.toFixed(6)}`;
223
- if (elements.valGMS) elements.valGMS.textContent = `${formatGMS(latGMS)}, ${formatGMS(lngGMS)}`;
224
- if (elements.valDM) elements.valDM.textContent = `${formatDM(latGMS)}, ${formatDM(lngGMS)}`;
225
- if (elements.valMaps) elements.valMaps.textContent = `${lat.toFixed(6)},${lng.toFixed(6)}`;
97
+ function updateGMSDisplay(lat, lng) {
98
+ const lGMS = decimalToGMS(lat, true);
99
+ const nGMS = decimalToGMS(lng, false);
100
+ setLatGMS(lGMS);
101
+ setLngGMS(nGMS);
226
102
  }
227
-
228
- function updateFromDD(lat, lng, updateInputs = true) {
229
- if (isNaN(lat) || isNaN(lng)) return;
230
-
231
- if (updateInputs) {
232
- elements.latDD.value = lat.toFixed(6);
233
- elements.lngDD.value = lng.toFixed(6);
234
- updateGMSInputs(lat, lng);
235
- } else if (mode === 'DD') {
236
- updateGMSInputs(lat, lng);
103
+ function updateResultDisplay(lat, lng) {
104
+ const lGMS = decimalToGMS(lat, true);
105
+ const nGMS = decimalToGMS(lng, false);
106
+ if (state.el.valDD) {
107
+ state.el.valDD.textContent = `${lat.toFixed(6)}, ${lng.toFixed(6)}`;
108
+ }
109
+ if (state.el.valGMS) {
110
+ state.el.valGMS.textContent = `${formatGMS(lGMS)}, ${formatGMS(nGMS)}`;
111
+ }
112
+ if (state.el.valDM) {
113
+ state.el.valDM.textContent = `${formatDM(lGMS)}, ${formatDM(nGMS)}`;
114
+ }
115
+ if (state.el.valMaps) {
116
+ state.el.valMaps.textContent = `${lat.toFixed(6)},${lng.toFixed(6)}`;
237
117
  }
238
-
239
- updateResultsDisplay(lat, lng);
240
- saveToHistory(lat, lng);
241
118
  }
242
-
243
- function getHemisphere(value, isLat) {
244
- if (value >= 0) return isLat ? 'N' : 'E';
245
- return isLat ? 'S' : 'W';
119
+ function setDDInputs(lat, lng) {
120
+ if (state.el.latDD) state.el.latDD.value = lat.toFixed(6);
121
+ if (state.el.lngDD) state.el.lngDD.value = lng.toFixed(6);
246
122
  }
247
-
248
- function decimalToGMS(d, isLat) {
249
- const h = getHemisphere(d, isLat);
250
- const absD = Math.abs(d);
251
- const g = Math.floor(absD);
252
- const mDecimal = (absD - g) * 60;
253
- const m = Math.floor(mDecimal);
254
- const s = (mDecimal - m) * 60;
255
- return { g, m, s, h, mDec: mDecimal };
123
+ function updateFromDD(lat, lng, upd=true) {
124
+ if (isNaN(lat) || isNaN(lng)) return;
125
+ if (upd) setDDInputs(lat, lng);
126
+ if (!upd && state.mode !== 'DD') return;
127
+ updateGMSDisplay(lat, lng);
128
+ updateResultDisplay(lat, lng);
129
+ saveHistory(lat, lng);
256
130
  }
257
-
258
- function gmsToDecimal(g, m, s, h) {
259
- let d = g + (m / 60) + (s / 3600);
260
- if (h === 'S' || h === 'W') d = -d;
261
- return d;
131
+ function createHistoryItem(item) {
132
+ return `<div class="history-item" data-id="${item.id}"><div class="hist-info" data-lat="${item.lat}" data-lng="${item.lng}">
133
+ <span class="hist-coords">${item.lat}, ${item.lng}</span><span class="hist-time">${item.time}</span></div><div class="hist-actions">
134
+ <button class="action-btn load-btn" data-lat="${item.lat}" data-lng="${item.lng}"><svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
135
+ <button class="action-btn delete-btn" data-id="${item.id}"><svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none"><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg></button></div></div>`;
262
136
  }
263
-
264
- function formatGMS(obj) {
265
- return `${obj.g}° ${obj.m}' ${obj.s.toFixed(2)}" ${obj.h}`;
137
+ function setupHistoryListeners() {
138
+ document.querySelectorAll('.load-btn').forEach(btn => {
139
+ btn.addEventListener('click', (evt) => {
140
+ evt.stopPropagation();
141
+ const lat = btn.getAttribute('data-lat');
142
+ const lng = btn.getAttribute('data-lng');
143
+ if (lat && lng) updateFromDD(parseFloat(lat), parseFloat(lng));
144
+ });
145
+ });
146
+ document.querySelectorAll('.delete-btn').forEach(btn => {
147
+ btn.addEventListener('click', (evt) => {
148
+ evt.stopPropagation();
149
+ const itemId = btn.getAttribute('data-id');
150
+ if (itemId) {
151
+ let history = JSON.parse(localStorage.getItem('gps_history') || '[]');
152
+ history = history.filter(it => it.id !== parseInt(itemId));
153
+ localStorage.setItem('gps_history', JSON.stringify(history));
154
+ renderHistory(history);
155
+ }
156
+ });
157
+ });
158
+ document.querySelectorAll('.hist-info').forEach(info => {
159
+ info.addEventListener('click', () => {
160
+ const lat = info.getAttribute('data-lat');
161
+ const lng = info.getAttribute('data-lng');
162
+ if (lat && lng) updateFromDD(parseFloat(lat), parseFloat(lng));
163
+ });
164
+ });
266
165
  }
267
-
268
- function formatDM(obj) {
269
- return `${obj.g}° ${obj.mDec.toFixed(3)}' ${obj.h}`;
166
+ function renderHistory(history) {
167
+ if (!state.el.historyList) return;
168
+ if (history.length === 0) {
169
+ state.el.historyList.innerHTML = `<div class="no-history">${state.ui.noHistory}</div>`;
170
+ } else {
171
+ state.el.historyList.innerHTML = history.map(createHistoryItem).join('');
172
+ }
173
+ setupHistoryListeners();
270
174
  }
271
-
272
- function saveToHistory(lat, lng) {
175
+ function saveHistory(lat, lng) {
273
176
  let history = JSON.parse(localStorage.getItem('gps_history') || '[]');
274
177
  const entry = {
275
178
  id: Date.now(),
@@ -277,382 +180,403 @@ const { ui } = Astro.props;
277
180
  lng: lng.toFixed(5),
278
181
  time: new Date().toLocaleTimeString()
279
182
  };
280
-
281
183
  if (history.length > 0 && history[0].lat === entry.lat && history[0].lng === entry.lng) return;
282
-
283
184
  history.unshift(entry);
284
185
  history = history.slice(0, 5);
285
186
  localStorage.setItem('gps_history', JSON.stringify(history));
286
187
  renderHistory(history);
287
188
  }
288
-
289
189
  function loadHistory() {
290
190
  const history = JSON.parse(localStorage.getItem('gps_history') || '[]');
291
191
  renderHistory(history);
292
192
  }
293
-
294
- function renderHistoryHTML(history) {
295
- return history.map(item => `
296
- <div class="history-item" data-id="${item.id}">
297
- <div class="hist-info" data-lat="${item.lat}" data-lng="${item.lng}">
298
- <span class="hist-coords">${item.lat}, ${item.lng}</span>
299
- <span class="hist-time">${item.time}</span>
300
- </div>
301
- <div class="hist-actions">
302
- <button class="action-btn load-btn" title="${uiLocal.load}" data-lat="${item.lat}" data-lng="${item.lng}">
303
- <svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
304
- </button>
305
- <button class="action-btn delete-btn" title="${uiLocal.delete}" data-id="${item.id}">
306
- <svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none"><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
307
- </button>
308
- </div>
309
- </div>
310
- `).join('');
193
+ function initMap() {
194
+ const mapEl = id('gpsMap');
195
+ if (!mapEl || !state.L) return;
196
+ state.map = state.L.map('gpsMap').setView([40.4168, -3.7038], 13);
197
+ state.L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
198
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
199
+ maxZoom: 19
200
+ }).addTo(state.map);
201
+ state.map.on('click', (evt) => updateFromDD(evt.latlng.lat, evt.latlng.lng));
311
202
  }
312
-
313
- function setupHistoryEventListeners() {
314
- document.querySelectorAll('.load-btn').forEach(btn => {
315
- btn.addEventListener('click', (e) => {
316
- e.stopPropagation();
317
- const lat = parseFloat(btn.getAttribute('data-lat')!);
318
- const lng = parseFloat(btn.getAttribute('data-lng')!);
319
- updateFromDD(lat, lng);
320
- });
203
+ function setupModeListeners() {
204
+ state.el.modeDD?.addEventListener('click', () => {
205
+ state.mode = 'DD';
206
+ state.el.modeDD?.classList.add('active');
207
+ state.el.modeGMS?.classList.remove('active');
208
+ if (state.el.ddInputs) state.el.ddInputs.style.display = 'grid';
209
+ if (state.el.gmsInputs) state.el.gmsInputs.style.display = 'none';
321
210
  });
322
-
323
- document.querySelectorAll('.delete-btn').forEach(btn => {
324
- btn.addEventListener('click', (e) => {
325
- e.stopPropagation();
326
- const id = parseInt(btn.getAttribute('data-id')!);
327
- let history = JSON.parse(localStorage.getItem('gps_history') || '[]');
328
- history = history.filter((item) => item.id !== id);
329
- localStorage.setItem('gps_history', JSON.stringify(history));
330
- renderHistory(history);
211
+ state.el.modeGMS?.addEventListener('click', () => {
212
+ state.mode = 'GMS';
213
+ state.el.modeGMS?.classList.add('active');
214
+ state.el.modeDD?.classList.remove('active');
215
+ if (state.el.ddInputs) state.el.ddInputs.style.display = 'none';
216
+ if (state.el.gmsInputs) state.el.gmsInputs.style.display = 'flex';
217
+ });
218
+ }
219
+ function setupInputListeners() {
220
+ state.el.btnMyLocation?.addEventListener('click', () => {
221
+ if ('geolocation' in navigator) {
222
+ navigator.geolocation.getCurrentPosition(pos => {
223
+ updateFromDD(pos.coords.latitude, pos.coords.longitude);
224
+ });
225
+ }
226
+ });
227
+ [state.el.latDD, state.el.lngDD].forEach(el => {
228
+ el?.addEventListener('input', () => {
229
+ if (state.mode === 'DD' && state.el.latDD && state.el.lngDD) {
230
+ updateFromDD(parseFloat(state.el.latDD.value), parseFloat(state.el.lngDD.value), false);
231
+ }
331
232
  });
332
233
  });
333
-
334
- document.querySelectorAll('.hist-info').forEach(info => {
335
- info.addEventListener('click', () => {
336
- const lat = parseFloat(info.getAttribute('data-lat')!);
337
- const lng = parseFloat(info.getAttribute('data-lng')!);
338
- updateFromDD(lat, lng);
234
+ }
235
+ function setupCopyListeners() {
236
+ document.querySelectorAll('.copy-btn').forEach(btn => {
237
+ btn.addEventListener('click', () => {
238
+ const targetId = btn.getAttribute('data-copy');
239
+ const text = targetId ? id(targetId)?.textContent : null;
240
+ if (text) {
241
+ navigator.clipboard.writeText(text);
242
+ const original = btn.innerHTML;
243
+ btn.innerHTML = state.ui.copied;
244
+ setTimeout(() => { btn.innerHTML = original; }, 2000);
245
+ }
339
246
  });
340
247
  });
248
+ id('clearHistory')?.addEventListener('click', () => {
249
+ localStorage.removeItem('gps_history');
250
+ loadHistory();
251
+ });
341
252
  }
342
-
343
- function renderHistory(history) {
344
- if (!elements.historyList) return;
345
- if (history.length === 0) {
346
- elements.historyList.innerHTML = `<div class="no-history">${uiLocal.noHistory}</div>`;
347
- return;
253
+ function setupAll() {
254
+ setupModeListeners();
255
+ setupInputListeners();
256
+ setupCopyListeners();
257
+ setupHistoryListeners();
258
+ }
259
+ function checkLeaflet() {
260
+ if (window.L) {
261
+ state.L = window.L;
262
+ initMap();
263
+ setupAll();
264
+ loadHistory();
265
+ updateFromDD(40.4168, -3.7038);
266
+ } else {
267
+ setTimeout(checkLeaflet, 100);
348
268
  }
349
- elements.historyList.innerHTML = renderHistoryHTML(history);
350
- setupHistoryEventListeners();
351
269
  }
352
-
353
- init();
270
+ initState();
271
+ checkLeaflet();
354
272
  </script>
355
273
 
356
274
  <style>
357
275
  .gps-converter-ui {
358
- --gps-accent: #0ea5e9;
359
- --gps-accent-glow: rgba(14, 165, 233, 0.15);
360
- --gps-bg: #fff;
361
- --gps-bg-muted: #f5f5f5;
362
- --gps-bg-surface: #eee;
363
- --gps-bg-overlay: #f0f0f0;
364
- --gps-text: #1a1a1a;
365
- --gps-text-muted: #4a4a4a;
366
- --gps-text-dim: #707070;
367
- --gps-border: #d0d0d0;
368
- --gps-border-light: #e8e8e8;
369
- --gps-shadow: 0 30px 60px rgba(0, 0, 0, 0.08);
370
- --gps-danger: #ef4444;
371
- --gps-danger-bg: rgba(239, 68, 68, 0.1);
372
-
373
- width: 100%;
374
- max-width: 1100px;
375
- margin: 0 auto;
276
+ --gps-accent: #0ea5e9;
277
+ --gps-accent-rgb: 14, 165, 233;
278
+ --gps-accent-glow: rgba(14, 165, 233, 0.15);
279
+ --gps-bg: #fff;
280
+ --gps-bg-muted: #f8fafc;
281
+ --gps-bg-surface: #f1f5f9;
282
+ --gps-bg-overlay: #fdfdfd;
283
+ --gps-text: #1e293b;
284
+ --gps-text-muted: #64748b;
285
+ --gps-text-dim: #94a3b8;
286
+ --gps-border: #e2e8f0;
287
+ --gps-border-light: #f1f5f9;
288
+ --gps-shadow: 0 40px 100px -20px rgba(0, 0, 0, 0.08);
289
+ --gps-danger: #ef4444;
290
+ --gps-danger-bg: rgba(239, 68, 68, 0.1);
291
+
292
+ width: 100%;
293
+ max-width: 1200px;
294
+ margin: 2rem auto;
295
+ padding: 0 1.5rem;
376
296
  }
377
297
 
378
298
  :global([data-theme="dark"]) .gps-converter-ui,
379
299
  :global(.theme-dark) .gps-converter-ui {
380
- --gps-bg: #1a1a1a;
381
- --gps-bg-muted: #2d2d2d;
382
- --gps-bg-surface: #3a3a3a;
383
- --gps-bg-overlay: #292929;
384
- --gps-text: #f5f5f5;
385
- --gps-text-muted: #b0b0b0;
386
- --gps-text-dim: #888;
387
- --gps-border: #4a4a4a;
388
- --gps-border-light: #525252;
389
- --gps-shadow: 0 30px 60px rgba(0, 0, 0, 0.08);
300
+ --gps-bg: #0f172a;
301
+ --gps-bg-muted: #1e293b;
302
+ --gps-bg-surface: #334155;
303
+ --gps-bg-overlay: #1e293b;
304
+ --gps-text: #f1f5f9;
305
+ --gps-text-muted: #94a3b8;
306
+ --gps-text-dim: #64748b;
307
+ --gps-border: #334155;
308
+ --gps-border-light: #1e293b;
309
+ --gps-shadow: 0 40px 100px -20px rgba(0, 0, 0, 0.4);
390
310
  }
391
311
 
392
312
  .gps-converter-ui .tech-mega-card {
393
- background: var(--gps-bg);
394
- backdrop-filter: blur(20px);
395
- border: 1px solid var(--gps-border);
396
- border-radius: 32px;
397
- box-shadow: var(--gps-shadow);
398
- overflow: hidden;
313
+ background: var(--gps-bg);
314
+ backdrop-filter: blur(24px) saturate(180%);
315
+ -webkit-backdrop-filter: blur(24px) saturate(180%);
316
+ border: 1px solid var(--gps-border);
317
+ border-radius: 40px;
318
+ box-shadow: var(--gps-shadow);
319
+ position: relative;
320
+ overflow: hidden;
321
+ }
322
+
323
+ .gps-converter-ui .tech-mega-card::before {
324
+ content: '';
325
+ position: absolute;
326
+ top: 0;
327
+ left: 0;
328
+ right: 0;
329
+ height: 6px;
330
+ background: linear-gradient(90deg, #0ea5e9, #6366f1, #0ea5e9);
331
+ background-size: 200% 100%;
332
+ animation: gradient-shift-gps 4s linear infinite;
333
+ z-index: 10;
334
+ }
335
+
336
+ @keyframes gradient-shift-gps {
337
+ 0% { background-position: 0% 50%; }
338
+ 100% { background-position: 200% 50%; }
399
339
  }
400
340
 
401
341
  .gps-converter-ui .card-grid {
402
- display: grid;
403
- grid-template-columns: 420px 1fr;
342
+ display: grid;
343
+ grid-template-columns: 400px 1fr;
344
+ min-height: 700px;
404
345
  }
405
346
 
406
347
  .gps-converter-ui .config-sidebar {
407
- padding: 2rem;
408
- background: var(--gps-bg-overlay);
409
- display: flex;
410
- flex-direction: column;
411
- gap: 2rem;
412
- border-right: 1px solid var(--gps-border-light);
413
- }
414
-
415
- :global([data-theme="dark"]) .gps-converter-ui .config-sidebar,
416
- :global(.theme-dark) .gps-converter-ui .config-sidebar {
417
- background: var(--gps-bg-surface);
418
- border-right-color: var(--gps-border-light);
348
+ padding: 3.5rem 3rem;
349
+ background: var(--gps-bg-overlay);
350
+ border-right: 1px solid var(--gps-border-light);
351
+ display: flex;
352
+ flex-direction: column;
353
+ gap: 3rem;
419
354
  }
420
355
 
421
356
  .gps-converter-ui .main-display {
422
- padding: 2rem;
423
- display: flex;
424
- flex-direction: column;
425
- gap: 2rem;
426
- background: var(--gps-bg);
427
- }
428
-
429
- .gps-converter-ui .tech-section {
430
- display: flex;
431
- flex-direction: column;
432
- gap: 1.5rem;
433
- }
434
-
435
- .gps-converter-ui .section-title {
436
- font-size: 0.9rem;
437
- font-weight: 800;
438
- color: var(--gps-text);
439
- text-transform: uppercase;
440
- letter-spacing: 0.05em;
441
- margin: 0;
357
+ padding: 3.5rem 3rem;
358
+ display: flex;
359
+ flex-direction: column;
360
+ gap: 3rem;
361
+ background: var(--gps-bg);
442
362
  }
443
363
 
444
364
  .gps-converter-ui .divider {
445
- height: 1px;
446
- width: 100%;
447
- background: linear-gradient(90deg, transparent, var(--gps-border-light), transparent);
448
- }
449
-
450
- .gps-converter-ui .compact-inputs {
451
- display: grid;
452
- grid-template-columns: 1fr 1fr;
453
- gap: 1rem;
454
- }
455
-
456
- .gps-converter-ui .input-block {
457
- display: flex;
458
- flex-direction: column;
459
- gap: 0.5rem;
460
- }
461
-
462
- .gps-converter-ui .field-label {
463
- font-size: 0.75rem;
464
- font-weight: 700;
465
- color: var(--gps-text-muted);
466
- text-transform: uppercase;
467
- }
468
-
469
- .gps-converter-ui .tech-input {
470
- width: 100%;
471
- padding: 0.75rem;
472
- background: var(--gps-bg-surface);
473
- border: 1px solid var(--gps-border);
474
- border-radius: 12px;
475
- font-weight: 600;
476
- color: var(--gps-text);
477
- }
478
-
479
- .gps-converter-ui .mode-switch {
480
- display: flex;
481
- background: var(--gps-bg-surface);
482
- padding: 0.3rem;
483
- border-radius: 14px;
484
- }
485
-
486
- .gps-converter-ui .mode-btn {
487
- flex: 1;
488
- padding: 0.6rem;
489
- border-radius: 10px;
490
- border: none;
491
- background: transparent;
492
- font-size: 0.8rem;
493
- font-weight: 700;
494
- color: var(--gps-text-muted);
495
- cursor: pointer;
496
- transition: all 0.2s;
497
- }
498
-
499
- .gps-converter-ui .mode-btn.active {
500
- background: var(--gps-bg);
501
- color: var(--gps-accent);
502
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
365
+ height: 1px;
366
+ width: 100%;
367
+ background: linear-gradient(90deg, transparent, var(--gps-border-light), transparent);
368
+ }
369
+
370
+ .gps-converter-ui :global(.tech-section) {
371
+ display: flex;
372
+ flex-direction: column;
373
+ gap: 1.5rem;
374
+ }
375
+
376
+ .gps-converter-ui :global(.section-title) {
377
+ font-size: 0.75rem;
378
+ font-weight: 800;
379
+ color: var(--gps-text-muted);
380
+ text-transform: uppercase;
381
+ letter-spacing: 0.15em;
382
+ }
383
+
384
+ .gps-converter-ui :global(.field-label) {
385
+ font-size: 0.7rem;
386
+ font-weight: 800;
387
+ color: var(--gps-text-dim);
388
+ text-transform: uppercase;
389
+ letter-spacing: 0.05em;
390
+ margin-bottom: 0.5rem;
391
+ display: block;
392
+ }
393
+
394
+ .gps-converter-ui :global(.tech-input) {
395
+ width: 100%;
396
+ padding: 1rem 1.25rem;
397
+ background: var(--gps-bg-surface);
398
+ border: 1px solid var(--gps-border);
399
+ border-radius: 16px;
400
+ font-weight: 700;
401
+ color: var(--gps-text);
402
+ font-size: 1rem;
403
+ transition: all 0.3s ease;
404
+ }
405
+
406
+ .gps-converter-ui :global(.tech-input:focus) {
407
+ outline: none;
408
+ border-color: var(--gps-accent);
409
+ box-shadow: 0 0 0 4px var(--gps-accent-glow);
410
+ background: var(--gps-bg);
411
+ }
412
+
413
+ .gps-converter-ui :global(.mode-switch) {
414
+ display: flex;
415
+ background: var(--gps-bg-surface);
416
+ padding: 0.4rem;
417
+ border-radius: 18px;
418
+ gap: 0.25rem;
419
+ }
420
+
421
+ .gps-converter-ui :global(.mode-btn) {
422
+ flex: 1;
423
+ padding: 0.75rem;
424
+ border-radius: 14px;
425
+ border: none;
426
+ background: transparent;
427
+ font-size: 0.75rem;
428
+ font-weight: 800;
429
+ color: var(--gps-text-muted);
430
+ cursor: pointer;
431
+ transition: all 0.3s ease;
432
+ }
433
+
434
+ .gps-converter-ui :global(.mode-btn.active) {
435
+ background: var(--gps-bg);
436
+ color: var(--gps-accent);
437
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
438
+ }
439
+
440
+ .gps-converter-ui :global(.map-container) {
441
+ max-width: 100%;
442
+ height: 400px;
443
+ border-radius: 32px;
444
+ overflow: hidden;
445
+ background: var(--gps-bg-surface);
446
+ border: 1px solid var(--gps-border-light);
447
+ }
448
+
449
+ .gps-converter-ui :global(.results-area) {
450
+ display: grid;
451
+ grid-template-columns: repeat(2, 1fr);
452
+ gap: 2rem;
453
+ }
454
+
455
+ .gps-converter-ui :global(.result-box) {
456
+ background: var(--gps-bg-overlay);
457
+ border: 1px solid var(--gps-border-light);
458
+ border-radius: 28px;
459
+ padding: 2.5rem;
460
+ display: flex;
461
+ flex-direction: column;
462
+ gap: 1rem;
463
+ transition: all 0.3s ease;
464
+ }
465
+
466
+ .gps-converter-ui :global(.result-box:hover) {
467
+ transform: translateY(-5px);
468
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.04);
469
+ border-color: var(--gps-accent);
470
+ }
471
+
472
+ .gps-converter-ui :global(.res-header) {
473
+ display: flex;
474
+ justify-content: space-between;
475
+ align-items: center;
476
+ }
477
+
478
+ .gps-converter-ui :global(.copy-btn) {
479
+ background: var(--gps-bg-surface);
480
+ border: 1px solid var(--gps-border);
481
+ color: var(--gps-text-muted);
482
+ padding: 0.5rem 1rem;
483
+ border-radius: 12px;
484
+ font-size: 0.7rem;
485
+ font-weight: 800;
486
+ cursor: pointer;
487
+ display: flex;
488
+ align-items: center;
489
+ gap: 0.5rem;
490
+ transition: all 0.3s ease;
491
+ }
492
+
493
+ .gps-converter-ui :global(.copy-btn:hover) {
494
+ background: var(--gps-accent);
495
+ color: white;
496
+ border-color: var(--gps-accent);
497
+ }
498
+
499
+ .gps-converter-ui :global(.val-display) {
500
+ font-size: 1.5rem;
501
+ font-weight: 900;
502
+ color: var(--gps-text);
503
+ word-break: break-all;
504
+ letter-spacing: -0.01em;
505
+ }
506
+
507
+ .gps-converter-ui :global(.history-item) {
508
+ padding: 1.25rem 1.5rem;
509
+ background: var(--gps-bg-surface);
510
+ border-radius: 20px;
511
+ display: flex;
512
+ justify-content: space-between;
513
+ align-items: center;
514
+ transition: all 0.3s ease;
515
+ border: 1px solid transparent;
516
+ }
517
+
518
+ .gps-converter-ui :global(.history-item:hover) {
519
+ background: var(--gps-bg);
520
+ border-color: var(--gps-accent);
521
+ transform: translateX(5px);
522
+ }
523
+
524
+ .gps-converter-ui :global(.hist-info) {
525
+ display: flex;
526
+ flex-direction: column;
527
+ cursor: pointer;
528
+ flex: 1;
503
529
  }
504
530
 
505
- .gps-converter-ui .map-container {
506
- width: 100%;
507
- height: 350px;
508
- border-radius: 20px;
509
- overflow: hidden;
510
- background: var(--gps-bg-surface);
511
- border: 1px solid var(--gps-border-light);
531
+ .gps-converter-ui :global(.hist-coords) {
532
+ font-size: 0.9rem;
533
+ font-weight: 800;
534
+ color: var(--gps-text);
535
+ }
536
+
537
+ .gps-converter-ui :global(.hist-time) {
538
+ font-size: 0.7rem;
539
+ color: var(--gps-text-dim);
540
+ font-weight: 700;
541
+ text-transform: uppercase;
542
+ }
543
+
544
+ .gps-converter-ui :global(.action-btn) {
545
+ background: var(--gps-bg-overlay);
546
+ border: 1px solid var(--gps-border);
547
+ padding: 0.6rem;
548
+ border-radius: 12px;
549
+ color: var(--gps-text-dim);
550
+ cursor: pointer;
551
+ display: flex;
552
+ align-items: center;
553
+ justify-content: center;
554
+ transition: all 0.2s ease;
555
+ }
556
+
557
+ .gps-converter-ui :global(.no-history) {
558
+ text-align: center;
559
+ padding: 3rem;
560
+ color: var(--gps-text-dim);
561
+ font-style: italic;
562
+ font-size: 0.9rem;
512
563
  }
513
564
 
514
- .gps-converter-ui .results-area {
515
- display: grid;
516
- grid-template-columns: 1fr 1fr;
517
- gap: 1.5rem;
518
- }
519
-
520
- .gps-converter-ui .result-box {
521
- background: var(--gps-bg-overlay);
522
- border: 1px solid var(--gps-border-light);
523
- border-radius: 20px;
524
- padding: 1.5rem;
525
- display: flex;
526
- flex-direction: column;
527
- gap: 0.75rem;
528
- }
529
-
530
- .gps-converter-ui .res-header {
531
- display: flex;
532
- justify-content: space-between;
533
- align-items: center;
534
- }
535
-
536
- .gps-converter-ui .res-label {
537
- font-size: 0.7rem;
538
- font-weight: 700;
539
- color: var(--gps-text-dim);
540
- text-transform: uppercase;
541
- }
542
-
543
- .gps-converter-ui .copy-btn {
544
- background: transparent;
545
- border: 1px solid var(--gps-border);
546
- color: var(--gps-text-muted);
547
- padding: 0.3rem 0.6rem;
548
- border-radius: 8px;
549
- font-size: 0.7rem;
550
- font-weight: 700;
551
- cursor: pointer;
552
- display: flex;
553
- align-items: center;
554
- gap: 0.4rem;
555
- transition: all 0.2s;
556
- }
557
-
558
- .gps-converter-ui .copy-btn:hover {
559
- background: var(--gps-accent);
560
- color: white;
561
- border-color: var(--gps-accent);
562
- }
563
-
564
- .gps-converter-ui .val-display {
565
- font-size: 1.35rem;
566
- font-weight: 800;
567
- color: var(--gps-text);
568
- }
569
-
570
- .gps-converter-ui .history-list {
571
- display: flex;
572
- flex-direction: column;
573
- gap: 0.5rem;
574
- }
575
-
576
- .gps-converter-ui .history-item {
577
- padding: 0.75rem 1rem;
578
- background: var(--gps-bg-surface);
579
- border-radius: 12px;
580
- display: flex;
581
- justify-content: space-between;
582
- align-items: center;
583
- transition: all 0.2s;
584
- }
585
-
586
- .gps-converter-ui .history-item:hover {
587
- background: var(--gps-border);
588
- }
589
-
590
- .gps-converter-ui .hist-info {
591
- display: flex;
592
- flex-direction: column;
593
- gap: 0.1rem;
594
- cursor: pointer;
595
- flex: 1;
596
- }
597
-
598
- .gps-converter-ui .hist-coords {
599
- font-size: 0.85rem;
600
- font-weight: 700;
601
- color: var(--gps-text);
602
- }
603
-
604
- .gps-converter-ui .hist-time {
605
- font-size: 0.65rem;
606
- color: var(--gps-text-dim);
607
- text-transform: uppercase;
608
- font-weight: 600;
609
- }
610
-
611
- .gps-converter-ui .hist-actions {
612
- display: flex;
613
- gap: 0.5rem;
614
- }
615
-
616
- .gps-converter-ui .action-btn {
617
- background: transparent;
618
- border: none;
619
- padding: 0.4rem;
620
- border-radius: 8px;
621
- color: var(--gps-text-dim);
622
- cursor: pointer;
623
- display: flex;
624
- align-items: center;
625
- justify-content: center;
626
- transition: all 0.2s;
627
- }
628
-
629
- .gps-converter-ui .load-btn:hover {
630
- color: var(--gps-accent);
631
- background: var(--gps-accent-glow);
632
- }
633
-
634
- .gps-converter-ui .delete-btn:hover {
635
- color: var(--gps-danger);
636
- background: var(--gps-danger-bg);
565
+ @media (max-width: 1200px) {
566
+ .gps-converter-ui .card-grid {
567
+ grid-template-columns: 1fr;
568
+ }
569
+ .gps-converter-ui .config-sidebar {
570
+ border-right: none;
571
+ border-bottom: 1px solid var(--gps-border-light);
572
+ }
637
573
  }
638
574
 
639
- @media (max-width: 992px) {
640
- .gps-converter-ui .card-grid {
641
- grid-template-columns: 1fr;
642
- }
643
-
644
- .gps-converter-ui .config-sidebar {
645
- border-right: none;
646
- border-bottom: 1px solid var(--gps-border-light);
647
- }
648
-
649
- :global([data-theme="dark"]) .gps-converter-ui .config-sidebar,
650
- :global(.theme-dark) .gps-converter-ui .config-sidebar {
651
- border-bottom-color: var(--gps-border-light);
652
- }
653
-
654
- .gps-converter-ui .results-area {
655
- grid-template-columns: 1fr;
656
- }
575
+ @media (max-width: 600px) {
576
+ .gps-converter-ui { padding: 0.5rem; }
577
+ .gps-converter-ui .config-sidebar,
578
+ .gps-converter-ui .main-display { padding: 2rem 1.5rem; }
579
+ .gps-converter-ui :global(.results-area) { grid-template-columns: 1fr; }
657
580
  }
658
581
  </style>
582
+