_footer.scss 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. // ==========================================================================
  2. // FOOTER
  3. // ==========================================================================
  4. @use '../abstracts/variables' as v;
  5. @use '../abstracts/mixins' as mix;
  6. @use 'sass:map';
  7. .footer {
  8. background: transparent;
  9. color: v.$white;
  10. position: relative;
  11. overflow: hidden;
  12. .footer-main {
  13. position: relative;
  14. z-index: 1;
  15. padding: map.get(v.$spacers, 8) 0 map.get(v.$spacers, 4);
  16. @include mix.respond-to-max('md') {
  17. padding: map.get(v.$spacers, 6) 0 map.get(v.$spacers, 3);
  18. }
  19. }
  20. .footer-content {
  21. display: grid;
  22. grid-template-columns: repeat(5, 1fr);
  23. gap: map.get(v.$spacers, 4);
  24. align-items: start;
  25. @include mix.respond-to-max('md') {
  26. grid-template-columns: repeat(3, 1fr);
  27. gap: map.get(v.$spacers, 4);
  28. }
  29. @include mix.respond-to-max('sm') {
  30. @include mix.flex(column, center, center);
  31. gap: map.get(v.$spacers, 4);
  32. }
  33. }
  34. .footer-section {
  35. width: 100%;
  36. max-width: 300px;
  37. }
  38. .footer-title {
  39. font-family: v.$font-family-heading;
  40. font-size: map.get(v.$font-sizes, 'lg');
  41. font-weight: map.get(v.$font-weights, 'semibold');
  42. margin-bottom: map.get(v.$spacers, 3);
  43. color: v.$white;
  44. position: relative;
  45. &::after {
  46. content: '';
  47. position: absolute;
  48. bottom: -8px;
  49. left: 0;
  50. width: 40px;
  51. height: 2px;
  52. background: v.$primary-light;
  53. }
  54. }
  55. .footer-about {
  56. .footer-logo {
  57. margin-bottom: map.get(v.$spacers, 3);
  58. .image {
  59. max-width: 150px;
  60. height: auto;
  61. }
  62. @include mix.respond-to-max('sm') {
  63. text-align: center;
  64. }
  65. }
  66. .footer-description {
  67. font-size: map.get(v.$font-sizes, 'sm');
  68. line-height: 1.6;
  69. margin-bottom: map.get(v.$spacers, 4);
  70. opacity: 0.9;
  71. color: rgba(v.$white, 0.9);
  72. }
  73. .footer-social {
  74. display: flex;
  75. flex-direction: column;
  76. margin-top: map.get(v.$spacers, 2);
  77. .social-label {
  78. display: block;
  79. font-size: map.get(v.$font-sizes, 'sm');
  80. font-weight: map.get(v.$font-weights, 'medium');
  81. margin-bottom: map.get(v.$spacers, 3);
  82. opacity: 0.9;
  83. color: rgba(v.$white, 0.9);
  84. }
  85. .social-links {
  86. @include mix.flex(row, flex-start, center);
  87. gap: map.get(v.$spacers, 2);
  88. flex-wrap: wrap;
  89. @include mix.respond-to-max('md') {
  90. @include mix.justify-content(center);
  91. }
  92. }
  93. .social-link {
  94. width: 40px;
  95. height: 40px;
  96. background: rgba(v.$white, 0.1);
  97. @include mix.border-radius(50%);
  98. @include mix.flex(row, center, center);
  99. color: v.$white;
  100. text-decoration: none;
  101. @include mix.transition(v.$transition-base);
  102. backdrop-filter: blur(10px);
  103. svg {
  104. width: 18px;
  105. height: 18px;
  106. fill: currentColor;
  107. }
  108. &:hover {
  109. background: rgba(v.$primary-light, 0.3);
  110. @include mix.transform(translateY(-3px));
  111. @include mix.box-shadow(0 5px 15px rgba(v.$primary-light, 0.3));
  112. }
  113. }
  114. }
  115. }
  116. .footer-menu {
  117. list-style: none;
  118. padding: 0;
  119. margin: 0;
  120. li {
  121. margin-bottom: map.get(v.$spacers, 2);
  122. &:last-child {
  123. margin-bottom: 0;
  124. }
  125. }
  126. @include mix.respond-to-max('sm') {
  127. padding-top: 10px;
  128. padding-left: 10px;
  129. }
  130. }
  131. .footer-link {
  132. color: rgba(v.$white, 0.8);
  133. font-size: map.get(v.$font-sizes, 'sm');
  134. text-decoration: none;
  135. @include mix.transition(v.$transition-base);
  136. display: inline-block;
  137. &:hover {
  138. color: v.$primary-light;
  139. @include mix.transform(translateX(5px));
  140. }
  141. }
  142. .footer-contact {
  143. @include mix.flex(column, center, center);
  144. .footer-contact-info {
  145. @include mix.flex(column, flex-start, stretch);
  146. gap: map.get(v.$spacers, 3);
  147. }
  148. .contact-item {
  149. @include mix.flex(row, flex-start, flex-start);
  150. gap: map.get(v.$spacers, 2);
  151. &:last-child {
  152. margin-bottom: 0;
  153. }
  154. .contact-icon {
  155. flex-shrink: 0;
  156. width: 20px;
  157. height: 20px;
  158. margin-top: 2px;
  159. color: v.$primary-light;
  160. svg {
  161. width: 100%;
  162. height: 100%;
  163. fill: currentColor;
  164. }
  165. }
  166. .contact-text {
  167. @include mix.flex(column, flex-start, flex-start);
  168. gap: map.get(v.$spacers, 1);
  169. .contact-label {
  170. font-size: map.get(v.$font-sizes, 'xs');
  171. font-weight: map.get(v.$font-weights, 'medium');
  172. color: v.$primary-light;
  173. text-transform: uppercase;
  174. letter-spacing: 0.5px;
  175. }
  176. .contact-value {
  177. font-size: map.get(v.$font-sizes, 'sm');
  178. font-weight: map.get(v.$font-weights, 'regular');
  179. color: rgba(v.$white, 0.9);
  180. line-height: 1.5;
  181. }
  182. }
  183. }
  184. }
  185. .footer-newsletter {
  186. .newsletter-description {
  187. font-size: map.get(v.$font-sizes, 'sm');
  188. line-height: 1.6;
  189. margin-bottom: map.get(v.$spacers, 3);
  190. opacity: 0.9;
  191. color: rgba(v.$white, 0.9);
  192. }
  193. .newsletter-form {
  194. margin-bottom: map.get(v.$spacers, 4);
  195. }
  196. .newsletter-input-group {
  197. @include mix.flex(row, flex-start, stretch);
  198. margin-bottom: map.get(v.$spacers, 2);
  199. background: rgba(v.$white, 0.1);
  200. @include mix.border-radius(50px);
  201. padding: 4px;
  202. backdrop-filter: blur(10px);
  203. }
  204. .newsletter-input {
  205. flex: 1;
  206. background: transparent;
  207. border: none;
  208. padding: map.get(v.$spacers, 2) map.get(v.$spacers, 3);
  209. color: v.$white;
  210. font-size: map.get(v.$font-sizes, 'sm');
  211. font-family: v.$font-family-sans;
  212. outline: none;
  213. @include mix.transition(v.$transition-base);
  214. &::placeholder {
  215. color: rgba(v.$white, 0.6);
  216. }
  217. &:focus {
  218. background: rgba(v.$white, 0.05);
  219. }
  220. }
  221. .newsletter-btn {
  222. width: 40px;
  223. height: 40px;
  224. background: v.$primary-light;
  225. border: none;
  226. @include mix.border-radius(50%);
  227. color: v.$white;
  228. cursor: pointer;
  229. @include mix.flex(row, center, center);
  230. @include mix.transition(v.$transition-base);
  231. svg {
  232. width: 16px;
  233. height: 16px;
  234. fill: currentColor;
  235. }
  236. &:hover {
  237. background: v.$primary;
  238. @include mix.transform(scale(1.05));
  239. }
  240. }
  241. .newsletter-checkbox {
  242. @include mix.flex(row, flex-start, flex-start);
  243. gap: map.get(v.$spacers, 2);
  244. font-size: map.get(v.$font-sizes, 'xs');
  245. cursor: pointer;
  246. line-height: 1.4;
  247. input {
  248. display: none;
  249. &:checked + .checkmark {
  250. background-color: v.$primary-light;
  251. border-color: v.$primary-light;
  252. &::after {
  253. display: block;
  254. }
  255. }
  256. }
  257. .checkmark {
  258. position: relative;
  259. width: 16px;
  260. height: 16px;
  261. border: 2px solid rgba(v.$white, 0.3);
  262. @include mix.border-radius(v.$border-radius-sm);
  263. @include mix.transition(v.$transition-base);
  264. flex-shrink: 0;
  265. margin-top: 1px;
  266. &::after {
  267. content: '';
  268. position: absolute;
  269. display: none;
  270. left: 4px;
  271. top: 0px;
  272. width: 4px;
  273. height: 8px;
  274. border: solid v.$white;
  275. border-width: 0 2px 2px 0;
  276. @include mix.transform(rotate(45deg));
  277. }
  278. }
  279. .checkbox-text {
  280. color: rgba(v.$white, 0.8);
  281. a {
  282. color: v.$primary-light;
  283. text-decoration: none;
  284. @include mix.transition(v.$transition-base);
  285. &:hover {
  286. text-decoration: underline;
  287. color: v.$white;
  288. }
  289. }
  290. }
  291. }
  292. .footer-copyright {
  293. margin-top: map.get(v.$spacers, 4);
  294. padding-top: map.get(v.$spacers, 3);
  295. border-top: 1px solid rgba(v.$white, 0.1);
  296. p {
  297. font-size: map.get(v.$font-sizes, 'sm');
  298. color: rgba(v.$white, 0.8);
  299. margin: 0;
  300. @include mix.respond-to-max('sm') {
  301. font-size: map.get(v.$font-sizes, 'xs');
  302. text-align: center;
  303. }
  304. }
  305. }
  306. }
  307. }
  308. .scroll-to-top {
  309. position: fixed;
  310. bottom: map.get(v.$spacers, 5);
  311. right: map.get(v.$spacers, 5);
  312. width: 50px;
  313. height: 50px;
  314. background: v.$primary;
  315. color: v.$white;
  316. border: none;
  317. @include mix.border-radius(50%);
  318. cursor: pointer;
  319. // Cambiado de display: none a opacity/visibility para mejores transiciones
  320. opacity: 0;
  321. visibility: hidden;
  322. @include mix.flex(row, center, center);
  323. @include mix.box-shadow(v.$box-shadow-lg);
  324. @include mix.transition(v.$transition-base);
  325. @include mix.transform(translateY(20px) scale(0.8));
  326. z-index: map.get(v.$z-indices, 'fixed');
  327. svg {
  328. width: 20px;
  329. height: 20px;
  330. fill: currentColor;
  331. @include mix.transition(transform 0.2s ease);
  332. }
  333. &:hover {
  334. background: v.$primary-dark;
  335. @include mix.transform(translateY(-3px) scale(1.05));
  336. @include mix.box-shadow(0 6px 20px rgba(v.$primary, 0.4));
  337. svg {
  338. @include mix.transform(translateY(-2px));
  339. }
  340. }
  341. &.show {
  342. opacity: 1;
  343. visibility: visible;
  344. @include mix.transform(translateY(0) scale(1));
  345. }
  346. // Estado activo/click
  347. &:active {
  348. @include mix.transform(translateY(-1px) scale(0.95));
  349. }
  350. // Estado de scrolling (previene múltiples clicks)
  351. &.scrolling {
  352. pointer-events: none;
  353. opacity: 0.7;
  354. svg {
  355. animation: scrolling-spin 0.8s linear infinite;
  356. }
  357. }
  358. // Accesibilidad - estado de focus
  359. &:focus {
  360. outline: none;
  361. @include mix.box-shadow(0 0 0 3px rgba(v.$primary, 0.3));
  362. }
  363. @include mix.respond-to-max('md') {
  364. bottom: map.get(v.$spacers, 4);
  365. right: map.get(v.$spacers, 4);
  366. width: 45px;
  367. height: 45px;
  368. svg {
  369. width: 18px;
  370. height: 18px;
  371. }
  372. }
  373. @include mix.respond-to-max('sm') {
  374. bottom: map.get(v.$spacers, 3);
  375. right: map.get(v.$spacers, 3);
  376. width: 40px;
  377. height: 40px;
  378. svg {
  379. width: 16px;
  380. height: 16px;
  381. }
  382. }
  383. }
  384. // Animación de rotación para el estado scrolling
  385. @keyframes scrolling-spin {
  386. 0% {
  387. @include mix.transform(rotate(0deg));
  388. }
  389. 100% {
  390. @include mix.transform(rotate(360deg));
  391. }
  392. }
  393. // Animación fadeInUp (mantiene tu animación original como alternativa)
  394. @keyframes fadeInUp {
  395. from {
  396. opacity: 0;
  397. @include mix.transform(translateY(20px));
  398. }
  399. to {
  400. opacity: 1;
  401. @include mix.transform(translateY(0));
  402. }
  403. }
  404. // Soporte para movimiento reducido
  405. @media (prefers-reduced-motion: reduce) {
  406. .scroll-to-top {
  407. @include mix.transition(opacity 0.2s ease);
  408. &.show {
  409. @include mix.transform(none);
  410. }
  411. &:hover {
  412. @include mix.transform(translateY(-3px));
  413. }
  414. svg {
  415. @include mix.transition(none);
  416. }
  417. }
  418. @keyframes scrolling-spin {
  419. 0%, 100% {
  420. @include mix.transform(none);
  421. }
  422. }
  423. }
  424. // ==========================================================================
  425. // ANIMATIONS
  426. // ==========================================================================
  427. @keyframes fadeInUp {
  428. from {
  429. opacity: 0;
  430. @include mix.transform(translateY(20px));
  431. }
  432. to {
  433. opacity: 1;
  434. @include mix.transform(translateY(0));
  435. }
  436. }
  437. .footer-section {
  438. animation: fadeInUp 0.6s ease-out;
  439. animation-fill-mode: both;
  440. &[data-aos] {
  441. animation: none; // Let AOS handle animations when available
  442. }
  443. }