diff --git a/CHANGELOG.md b/CHANGELOG.md index 342b58261..1816bb6c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.3.0] - Unreleased +The Trips Update Release + +Trips are now using MapLibre instead of Leaflet to provide same smooth experience as the Map V2. + +Each day of a trip now has its own card on the trip page with where user can leave a note for that day. Each day is colored in different color on the map to easily distinguish them. Timeline and Replay functionality is now available on the trip page as well, so you can easily see how your location changed during the trip and replay it if you want. + ### Added - Per-user timezone setting. Users can now select their timezone from Settings > General, and all dates/times across the app (including background jobs and API responses) will respect it. Defaults to the server's `TIME_ZONE` environment variable for existing users. @@ -20,6 +26,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - The `STORE_GEODATA` setting now correctly controls whether geodata is written during reverse geocoding. - Dropped unused `idx_points_user_city` database index (304 MB) and replaced the full `reverse_geocoded_at` index (1,149 MB) with a smaller partial index covering only un-geocoded rows. +### Fixed + +- Countries that were not showed as flags before now fixed. + ## [1.2.0] - 2026-02-15 @@ -30,6 +40,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Countries flags as SVGs instead of emojis. - Map v2 requires WebGL support, so if user's browser doesn't support it or it's disabled, they will see a warning message with a link to the list of supported browsers. - New **Insights API** (`GET /api/v1/insights`) returning year overview with totals, activity heatmap, and streak data for the mobile app. - New **Insights Details API** (`GET /api/v1/insights/details`) returning year-over-year comparison and travel patterns for the mobile app. @@ -68,6 +79,11 @@ In Map V2 Tools, user can now enable Timeline tool, which allows to quickly navi - Zooming animation is disabled on Map V2 loading #2219 - Exporting points to GPX and GeoJSON now works better and faster for large numbers of points by processing the export in chunks to reduce memory usage. #2161 +- Default color for Tracks layer on Map V2 is now set to blue instead of red. + +## Removed + +- `MIN_MINUTES_SPENT_IN_CITY` env variable is removed. It is now user-configurable in the Map v2 Settings panel. You can safely remove the `MIN_MINUTES_SPENT_IN_CITY` variable from your environment variables if you had it set before. ## [1.0.4] - 2026-02-01 diff --git a/app/assets/builds/tailwind.css b/app/assets/builds/tailwind.css index b82adaa88..85a4c37cc 100644 --- a/app/assets/builds/tailwind.css +++ b/app/assets/builds/tailwind.css @@ -3,4 +3,4 @@ );grid-template-rows:var(--timeline-row-start,minmax(0,1fr)) auto var( --timeline-row-end,minmax(0,1fr) );position:relative}.timeline>li>hr{border-width:0;width:100%}:where(.timeline>li>hr):first-child{grid-column-start:1;grid-row-start:2}:where(.timeline>li>hr):last-child{grid-column-end:none;grid-column-start:3;grid-row-end:auto;grid-row-start:2}.timeline-start{align-self:flex-end;grid-column-end:4;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:center;margin:.25rem}.timeline-middle{grid-column-start:2;grid-row-start:2}.timeline-end{align-self:flex-start;grid-column-end:4;grid-column-start:1;grid-row-end:4;grid-row-start:3;justify-self:center;margin:.25rem}.toast{display:flex;flex-direction:column;gap:.5rem;min-width:-moz-fit-content;min-width:fit-content;padding:1rem;position:fixed;white-space:nowrap}.toggle{flex-shrink:0;--tglbg:var(--fallback-b1,oklch(var(--b1)/1));--handleoffset:1.5rem;--handleoffsetcalculator:calc(var(--handleoffset)*-1);--togglehandleborder:0 0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:currentColor;border-color:currentColor;border-radius:var(--rounded-badge,1.9rem);border-width:1px;box-shadow:var(--handleoffsetcalculator) 0 0 2px var(--tglbg) inset,0 0 0 2px var(--tglbg) inset,var(--togglehandleborder);color:var(--fallback-bc,oklch(var(--bc)/.5));cursor:pointer;height:1.5rem;transition:background,box-shadow var(--animation-input,.2s) ease-out;width:3rem}.alert-info{border-color:var(--fallback-in,oklch(var(--in)/.2));--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)));--alert-bg:var(--fallback-in,oklch(var(--in)/1));--alert-bg-mix:var(--fallback-b1,oklch(var(--b1)/1))}.alert-success{border-color:var(--fallback-su,oklch(var(--su)/.2));--tw-text-opacity:1;color:var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)));--alert-bg:var(--fallback-su,oklch(var(--su)/1));--alert-bg-mix:var(--fallback-b1,oklch(var(--b1)/1))}.alert-warning{border-color:var(--fallback-wa,oklch(var(--wa)/.2));--tw-text-opacity:1;color:var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)));--alert-bg:var(--fallback-wa,oklch(var(--wa)/1));--alert-bg-mix:var(--fallback-b1,oklch(var(--b1)/1))}.alert-error{border-color:var(--fallback-er,oklch(var(--er)/.2));--tw-text-opacity:1;color:var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));--alert-bg:var(--fallback-er,oklch(var(--er)/1));--alert-bg-mix:var(--fallback-b1,oklch(var(--b1)/1))}.avatar-group :where(.avatar){border-radius:9999px;border-width:4px;overflow:hidden;--tw-border-opacity:1;border-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-border-opacity)))}.badge-neutral{background-color:var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));border-color:var(--fallback-n,oklch(var(--n)/var(--tw-border-opacity)));color:var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)))}.badge-neutral,.badge-primary{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1}.badge-primary{background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}.badge-secondary{background-color:var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity)));border-color:var(--fallback-s,oklch(var(--s)/var(--tw-border-opacity)));color:var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity)))}.badge-accent,.badge-secondary{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1}.badge-accent{background-color:var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity)));border-color:var(--fallback-a,oklch(var(--a)/var(--tw-border-opacity)));color:var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity)))}.badge-info{background-color:var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)));color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)))}.badge-info,.badge-success{border-color:transparent;--tw-bg-opacity:1;--tw-text-opacity:1}.badge-success{background-color:var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)));color:var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)))}.badge-warning{background-color:var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)));color:var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)))}.badge-error,.badge-warning{border-color:transparent;--tw-bg-opacity:1;--tw-text-opacity:1}.badge-error{background-color:var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity)));color:var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)))}.badge-ghost{--tw-border-opacity:1;border-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)))}.badge-outline{border-color:currentColor;--tw-border-opacity:0.5;background-color:transparent;color:currentColor}.badge-outline.badge-neutral{--tw-text-opacity:1;color:var(--fallback-n,oklch(var(--n)/var(--tw-text-opacity)))}.badge-outline.badge-primary{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity)))}.badge-outline.badge-secondary{--tw-text-opacity:1;color:var(--fallback-s,oklch(var(--s)/var(--tw-text-opacity)))}.badge-outline.badge-accent{--tw-text-opacity:1;color:var(--fallback-a,oklch(var(--a)/var(--tw-text-opacity)))}.badge-outline.badge-info{--tw-text-opacity:1;color:var(--fallback-in,oklch(var(--in)/var(--tw-text-opacity)))}.badge-outline.badge-success{--tw-text-opacity:1;color:var(--fallback-su,oklch(var(--su)/var(--tw-text-opacity)))}.badge-outline.badge-warning{--tw-text-opacity:1;color:var(--fallback-wa,oklch(var(--wa)/var(--tw-text-opacity)))}.badge-outline.badge-error{--tw-text-opacity:1;color:var(--fallback-er,oklch(var(--er)/var(--tw-text-opacity)))}.btm-nav>:where(.active){border-top-width:2px;--tw-bg-opacity:1;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)))}.btm-nav>.disabled,.btm-nav>[disabled]{pointer-events:none;--tw-border-opacity:0;background-color:var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));--tw-bg-opacity:0.1;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));--tw-text-opacity:0.2}.btm-nav>* .\!label{font-size:1rem!important;line-height:1.5rem!important}.btm-nav>* .label{font-size:1rem;line-height:1.5rem}.btn:active:focus,.btn:active:hover{animation:button-pop 0s ease-out;transform:scale(var(--btn-focus-scale,.97))}@supports not (color:oklch(0 0 0)){.btn{background-color:var(--btn-color,var(--fallback-b2));border-color:var(--btn-color,var(--fallback-b2))}.btn-primary{--btn-color:var(--fallback-p)}.btn-neutral{--btn-color:var(--fallback-n)}.btn-info{--btn-color:var(--fallback-in)}.btn-success{--btn-color:var(--fallback-su)}.btn-warning{--btn-color:var(--fallback-wa)}.btn-error{--btn-color:var(--fallback-er)}}@supports (color:color-mix(in oklab,black,black)){.btn-active{background-color:color-mix(in oklab,oklch(var(--btn-color,var(--b3))/var(--tw-bg-opacity,1)) 90%,#000);border-color:color-mix(in oklab,oklch(var(--btn-color,var(--b3))/var(--tw-border-opacity,1)) 90%,#000)}.btn-outline.btn-primary.btn-active{background-color:color-mix(in oklab,var(--fallback-p,oklch(var(--p)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-p,oklch(var(--p)/1)) 90%,#000)}.btn-outline.btn-secondary.btn-active{background-color:color-mix(in oklab,var(--fallback-s,oklch(var(--s)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-s,oklch(var(--s)/1)) 90%,#000)}.btn-outline.btn-accent.btn-active{background-color:color-mix(in oklab,var(--fallback-a,oklch(var(--a)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-a,oklch(var(--a)/1)) 90%,#000)}.btn-outline.btn-success.btn-active{background-color:color-mix(in oklab,var(--fallback-su,oklch(var(--su)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-su,oklch(var(--su)/1)) 90%,#000)}.btn-outline.btn-info.btn-active{background-color:color-mix(in oklab,var(--fallback-in,oklch(var(--in)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-in,oklch(var(--in)/1)) 90%,#000)}.btn-outline.btn-warning.btn-active{background-color:color-mix(in oklab,var(--fallback-wa,oklch(var(--wa)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-wa,oklch(var(--wa)/1)) 90%,#000)}.btn-outline.btn-error.btn-active{background-color:color-mix(in oklab,var(--fallback-er,oklch(var(--er)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-er,oklch(var(--er)/1)) 90%,#000)}}.btn:focus-visible{outline-offset:2px;outline-style:solid;outline-width:2px}.btn-primary{--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));outline-color:var(--fallback-p,oklch(var(--p)/1))}@supports (color:oklch(0 0 0)){.btn-primary{--btn-color:var(--p)}.btn-neutral{--btn-color:var(--n)}.btn-info{--btn-color:var(--in)}.btn-success{--btn-color:var(--su)}.btn-warning{--btn-color:var(--wa)}.btn-error{--btn-color:var(--er)}}.btn-neutral{--tw-text-opacity:1;color:var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));outline-color:var(--fallback-n,oklch(var(--n)/1))}.btn-info{--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)));outline-color:var(--fallback-in,oklch(var(--in)/1))}.btn-success{--tw-text-opacity:1;color:var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)));outline-color:var(--fallback-su,oklch(var(--su)/1))}.btn-warning{--tw-text-opacity:1;color:var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)));outline-color:var(--fallback-wa,oklch(var(--wa)/1))}.btn-error{--tw-text-opacity:1;color:var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));outline-color:var(--fallback-er,oklch(var(--er)/1))}.btn.glass{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);outline-color:currentColor}.btn.glass.btn-active{--glass-opacity:25%;--glass-border-opacity:15%}.btn-ghost{background-color:transparent;border-color:transparent;border-width:1px;color:currentColor;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);outline-color:currentColor}.btn-ghost.btn-active{background-color:var(--fallback-bc,oklch(var(--bc)/.2));border-color:transparent}.btn-link.btn-active{background-color:transparent;border-color:transparent;text-decoration-line:underline}.btn-outline{background-color:transparent;border-color:currentColor;--tw-text-opacity:1;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.btn-outline.btn-active{--tw-border-opacity:1;border-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-b1,oklch(var(--b1)/var(--tw-text-opacity)))}.btn-outline.btn-primary{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity)))}.btn-outline.btn-primary.btn-active{--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}.btn-outline.btn-secondary{--tw-text-opacity:1;color:var(--fallback-s,oklch(var(--s)/var(--tw-text-opacity)))}.btn-outline.btn-secondary.btn-active{--tw-text-opacity:1;color:var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity)))}.btn-outline.btn-accent{--tw-text-opacity:1;color:var(--fallback-a,oklch(var(--a)/var(--tw-text-opacity)))}.btn-outline.btn-accent.btn-active{--tw-text-opacity:1;color:var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity)))}.btn-outline.btn-success{--tw-text-opacity:1;color:var(--fallback-su,oklch(var(--su)/var(--tw-text-opacity)))}.btn-outline.btn-success.btn-active{--tw-text-opacity:1;color:var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)))}.btn-outline.btn-info{--tw-text-opacity:1;color:var(--fallback-in,oklch(var(--in)/var(--tw-text-opacity)))}.btn-outline.btn-info.btn-active{--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)))}.btn-outline.btn-warning{--tw-text-opacity:1;color:var(--fallback-wa,oklch(var(--wa)/var(--tw-text-opacity)))}.btn-outline.btn-warning.btn-active{--tw-text-opacity:1;color:var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)))}.btn-outline.btn-error{--tw-text-opacity:1;color:var(--fallback-er,oklch(var(--er)/var(--tw-text-opacity)))}.btn-outline.btn-error.btn-active{--tw-text-opacity:1;color:var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)))}.btn.btn-disabled,.btn:disabled,.btn[disabled]{--tw-border-opacity:0;background-color:var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));--tw-bg-opacity:0.2;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));--tw-text-opacity:0.2}.btn:is(input[type=checkbox]:checked),.btn:is(input[type=radio]:checked){--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}.btn:is(input[type=checkbox]:checked):focus-visible,.btn:is(input[type=radio]:checked):focus-visible{outline-color:var(--fallback-p,oklch(var(--p)/1))}@keyframes button-pop{0%{transform:scale(var(--btn-focus-scale,.98))}40%{transform:scale(1.02)}to{transform:scale(1)}}.card :where(figure:first-child){border-end-end-radius:unset;border-end-start-radius:unset;border-start-end-radius:inherit;border-start-start-radius:inherit;overflow:hidden}.card :where(figure:last-child){border-end-end-radius:inherit;border-end-start-radius:inherit;border-start-end-radius:unset;border-start-start-radius:unset;overflow:hidden}.card:focus-visible{outline:2px solid currentColor;outline-offset:2px}.card.bordered{border-width:1px;--tw-border-opacity:1;border-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)))}.card.compact .card-body{font-size:.875rem;line-height:1.25rem;padding:1rem}.card-title{align-items:center;display:flex;font-size:1.25rem;font-weight:600;gap:.5rem;line-height:1.75rem}.card.image-full :where(figure){border-radius:inherit;overflow:hidden}.checkbox:focus{box-shadow:none}.checkbox:focus-visible{outline-color:var(--fallback-bc,oklch(var(--bc)/1));outline-offset:2px;outline-style:solid;outline-width:2px}.checkbox:checked,.checkbox[aria-checked=true],.checkbox[checked=true]{animation:checkmark var(--animation-input,.2s) ease-out;background-color:var(--chkbg);background-image:linear-gradient(-45deg,transparent 65%,var(--chkbg) 65.99%),linear-gradient(45deg,transparent 75%,var(--chkbg) 75.99%),linear-gradient(-45deg,var(--chkbg) 40%,transparent 40.99%),linear-gradient(45deg,var(--chkbg) 30%,var(--chkfg) 30.99%,var(--chkfg) 40%,transparent 40.99%),linear-gradient(-45deg,var(--chkfg) 50%,var(--chkbg) 50.99%);background-repeat:no-repeat}.checkbox:indeterminate{--tw-bg-opacity:1;animation:checkmark var(--animation-input,.2s) ease-out;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));background-image:linear-gradient(90deg,transparent 80%,var(--chkbg) 80%),linear-gradient(-90deg,transparent 80%,var(--chkbg) 80%),linear-gradient(0deg,var(--chkbg) 43%,var(--chkfg) 43%,var(--chkfg) 57%,var(--chkbg) 57%);background-repeat:no-repeat}.checkbox-primary{--chkbg:var(--fallback-p,oklch(var(--p)/1));--chkfg:var(--fallback-pc,oklch(var(--pc)/1));--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)))}.checkbox-primary:focus-visible{outline-color:var(--fallback-p,oklch(var(--p)/1))}.checkbox-primary:checked,.checkbox-primary[aria-checked=true],.checkbox-primary[checked=true]{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}.checkbox:disabled{border-color:transparent;cursor:not-allowed;--tw-bg-opacity:1;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));opacity:.2}@keyframes checkmark{0%{background-position-y:5px}50%{background-position-y:-2px}to{background-position-y:0}}details.collapse{width:100%}details.collapse summary{display:block;outline:2px solid transparent;outline-offset:2px;position:relative}details.collapse summary::-webkit-details-marker{display:none}.collapse:focus-visible{outline-color:var(--fallback-bc,oklch(var(--bc)/1));outline-offset:2px;outline-style:solid;outline-width:2px}.collapse:has(.collapse-title:focus-visible),.collapse:has(>input[type=checkbox]:focus-visible),.collapse:has(>input[type=radio]:focus-visible){outline-color:var(--fallback-bc,oklch(var(--bc)/1));outline-offset:2px;outline-style:solid;outline-width:2px}.collapse-arrow>.collapse-title:after{--tw-translate-y:-100%;--tw-rotate:45deg;box-shadow:2px 2px;content:"";top:1.9rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));transform-origin:75% 75%;transition-duration:.15s;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(0,0,.2,1)}.collapse-arrow>.collapse-title:after,.collapse-plus>.collapse-title:after{display:block;height:.5rem;inset-inline-end:1.4rem;pointer-events:none;position:absolute;transition-property:all;width:.5rem}.collapse-plus>.collapse-title:after{content:"+";top:.9rem;transition-duration:.3s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(0,0,.2,1)}.collapse:not(.collapse-open):not(.collapse-close)>.collapse-title,.collapse:not(.collapse-open):not(.collapse-close)>input[type=checkbox],.collapse:not(.collapse-open):not(.collapse-close)>input[type=radio]:not(:checked){cursor:pointer}.collapse:focus:not(.collapse-open):not(.collapse-close):not(.collapse[open])>.collapse-title{cursor:unset}.collapse-title{position:relative}:where(.collapse>input[type=checkbox]),:where(.collapse>input[type=radio]){z-index:1}.collapse-title,:where(.collapse>input[type=checkbox]),:where(.collapse>input[type=radio]){min-height:3.75rem;padding:1rem;padding-inline-end:3rem;transition:background-color .2s ease-out;width:100%}.collapse-open>:where(.collapse-content),.collapse:focus:not(.collapse-close)>:where(.collapse-content),.collapse:not(.collapse-close)>:where(input[type=checkbox]:checked~.collapse-content),.collapse:not(.collapse-close)>:where(input[type=radio]:checked~.collapse-content),.collapse[open]>:where(.collapse-content){padding-bottom:1rem;transition:padding .2s ease-out,background-color .2s ease-out}.collapse-arrow:focus:not(.collapse-close)>.collapse-title:after,.collapse-arrow:not(.collapse-close)>input[type=checkbox]:checked~.collapse-title:after,.collapse-arrow:not(.collapse-close)>input[type=radio]:checked~.collapse-title:after,.collapse-open.collapse-arrow>.collapse-title:after,.collapse[open].collapse-arrow>.collapse-title:after{--tw-translate-y:-50%;--tw-rotate:225deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.collapse-open.collapse-plus>.collapse-title:after,.collapse-plus:focus:not(.collapse-close)>.collapse-title:after,.collapse-plus:not(.collapse-close)>input[type=checkbox]:checked~.collapse-title:after,.collapse-plus:not(.collapse-close)>input[type=radio]:checked~.collapse-title:after,.collapse[open].collapse-plus>.collapse-title:after{content:"−"}.divider:not(:empty){gap:1rem}.drawer-toggle:focus-visible~.drawer-content label.drawer-button{outline-offset:2px;outline-style:solid;outline-width:2px}.dropdown.dropdown-open .dropdown-content,.dropdown:focus .dropdown-content,.dropdown:focus-within .dropdown-content{--tw-scale-x:1;--tw-scale-y:1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.file-input-bordered{--tw-border-opacity:0.2}.file-input:focus{outline-color:var(--fallback-bc,oklch(var(--bc)/.2));outline-offset:2px;outline-style:solid;outline-width:2px}.file-input-disabled,.file-input[disabled]{cursor:not-allowed;--tw-border-opacity:1;border-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));--tw-text-opacity:0.2}.file-input-disabled::-moz-placeholder,.file-input[disabled]::-moz-placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.file-input-disabled::placeholder,.file-input[disabled]::placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.file-input-disabled::file-selector-button,.file-input[disabled]::file-selector-button{--tw-border-opacity:0;background-color:var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));--tw-bg-opacity:0.2;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));--tw-text-opacity:0.2}.footer-title{font-weight:700;margin-bottom:.5rem;opacity:.6;text-transform:uppercase}.label-text{font-size:.875rem;line-height:1.25rem}.label-text,.label-text-alt{--tw-text-opacity:1;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)))}.label-text-alt{font-size:.75rem;line-height:1rem}.\!input input{--tw-bg-opacity:1!important;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)))!important;background-color:transparent!important}.input input{--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));background-color:transparent}.\!input input:focus{outline:2px solid transparent!important;outline-offset:2px!important}.input input:focus{outline:2px solid transparent;outline-offset:2px}.\!input[list]::-webkit-calendar-picker-indicator{line-height:1em!important}.input[list]::-webkit-calendar-picker-indicator{line-height:1em}.input-bordered{border-color:var(--fallback-bc,oklch(var(--bc)/.2))}.input:focus,.input:focus-within{border-color:var(--fallback-bc,oklch(var(--bc)/.2));box-shadow:none;outline-color:var(--fallback-bc,oklch(var(--bc)/.2));outline-offset:2px;outline-style:solid;outline-width:2px}.\!input:focus,.\!input:focus-within{border-color:var(--fallback-bc,oklch(var(--bc)/.2))!important;box-shadow:none!important;outline-color:var(--fallback-bc,oklch(var(--bc)/.2))!important;outline-offset:2px!important;outline-style:solid!important;outline-width:2px!important}.input-primary{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)))}.input-primary:focus,.input-primary:focus-within{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));outline-color:var(--fallback-p,oklch(var(--p)/1))}.input-error{--tw-border-opacity:1;border-color:var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity)))}.input-error:focus,.input-error:focus-within{--tw-border-opacity:1;border-color:var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity)));outline-color:var(--fallback-er,oklch(var(--er)/1))}.input-disabled,.input:disabled,.input[disabled]{cursor:not-allowed;--tw-border-opacity:1;border-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));color:var(--fallback-bc,oklch(var(--bc)/.4))}.\!input:disabled,.\!input[disabled]{cursor:not-allowed!important;--tw-border-opacity:1!important;border-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)))!important;--tw-bg-opacity:1!important;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)))!important;color:var(--fallback-bc,oklch(var(--bc)/.4))!important}.input-disabled::-moz-placeholder,.input:disabled::-moz-placeholder,.input[disabled]::-moz-placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.input-disabled::placeholder,.input:disabled::placeholder,.input[disabled]::placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.\!input:disabled::-moz-placeholder,.\!input[disabled]::-moz-placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)))!important;--tw-placeholder-opacity:0.2!important}.\!input:disabled::placeholder,.\!input[disabled]::placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)))!important;--tw-placeholder-opacity:0.2!important}.\!input::-webkit-date-and-time-value{text-align:inherit!important}.input::-webkit-date-and-time-value{text-align:inherit}.join>:where(:not(:first-child)){margin-bottom:0;margin-top:0;margin-inline-start:-1px}.join-item:focus{isolation:isolate}.link-primary{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity)))}@supports (color:color-mix(in oklab,black,black)){@media (hover:hover){.link-primary:hover{color:color-mix(in oklab,var(--fallback-p,oklch(var(--p)/1)) 80%,#000)}.link-info:hover{color:color-mix(in oklab,var(--fallback-in,oklch(var(--in)/1)) 80%,#000)}}}.link-info{--tw-text-opacity:1;color:var(--fallback-in,oklch(var(--in)/var(--tw-text-opacity)))}.link:focus{outline:2px solid transparent;outline-offset:2px}.link:focus-visible{outline:2px solid currentColor;outline-offset:2px}.loading{aspect-ratio:1/1;background-color:currentColor;display:inline-block;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:100%;mask-size:100%;pointer-events:none;width:1.5rem}.loading,.loading-spinner{-webkit-mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' stroke='%23000'%3E%3Cstyle%3E@keyframes spinner_zKoa{to{transform:rotate(360deg)}}@keyframes spinner_YpZS{0%25{stroke-dasharray:0 150;stroke-dashoffset:0}47.5%25{stroke-dasharray:42 150;stroke-dashoffset:-16}95%25,to{stroke-dasharray:42 150;stroke-dashoffset:-59}}%3C/style%3E%3Cg style='transform-origin:center;animation:spinner_zKoa 2s linear infinite'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' class='spinner_V8m1' style='stroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite'/%3E%3C/g%3E%3C/svg%3E");mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' stroke='%23000'%3E%3Cstyle%3E@keyframes spinner_zKoa{to{transform:rotate(360deg)}}@keyframes spinner_YpZS{0%25{stroke-dasharray:0 150;stroke-dashoffset:0}47.5%25{stroke-dasharray:42 150;stroke-dashoffset:-16}95%25,to{stroke-dasharray:42 150;stroke-dashoffset:-59}}%3C/style%3E%3Cg style='transform-origin:center;animation:spinner_zKoa 2s linear infinite'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' class='spinner_V8m1' style='stroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite'/%3E%3C/g%3E%3C/svg%3E")}.loading-dots{-webkit-mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cstyle%3E@keyframes spinner_8HQG{0%25,57.14%25{animation-timing-function:cubic-bezier(.33,.66,.66,1);transform:translate(0)}28.57%25{animation-timing-function:cubic-bezier(.33,0,.66,.33);transform:translateY(-6px)}to{transform:translate(0)}}.spinner_qM83{animation:spinner_8HQG 1.05s infinite}%3C/style%3E%3Ccircle cx='4' cy='12' r='3' class='spinner_qM83'/%3E%3Ccircle cx='12' cy='12' r='3' class='spinner_qM83' style='animation-delay:.1s'/%3E%3Ccircle cx='20' cy='12' r='3' class='spinner_qM83' style='animation-delay:.2s'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cstyle%3E@keyframes spinner_8HQG{0%25,57.14%25{animation-timing-function:cubic-bezier(.33,.66,.66,1);transform:translate(0)}28.57%25{animation-timing-function:cubic-bezier(.33,0,.66,.33);transform:translateY(-6px)}to{transform:translate(0)}}.spinner_qM83{animation:spinner_8HQG 1.05s infinite}%3C/style%3E%3Ccircle cx='4' cy='12' r='3' class='spinner_qM83'/%3E%3Ccircle cx='12' cy='12' r='3' class='spinner_qM83' style='animation-delay:.1s'/%3E%3Ccircle cx='20' cy='12' r='3' class='spinner_qM83' style='animation-delay:.2s'/%3E%3C/svg%3E")}.loading-xs{width:1rem}.loading-sm{width:1.25rem}.loading-md{width:1.5rem}.loading-lg{width:2.5rem}:where(.menu li:empty){--tw-bg-opacity:1;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));height:1px;margin:.5rem 1rem;opacity:.1}.menu :where(li ul):before{bottom:.75rem;inset-inline-start:0;position:absolute;top:.75rem;width:1px;--tw-bg-opacity:1;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));content:"";opacity:.1}.menu :where(li:not(.menu-title)>:not(ul,details,.menu-title,.btn)),.menu :where(li:not(.menu-title)>details>summary:not(.menu-title)){border-radius:var(--rounded-btn,.5rem);padding:.5rem 1rem;text-align:start;text-wrap:balance;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(0,0,.2,1)}:where(.menu li:not(.menu-title,.disabled)>:not(ul,details,.menu-title)):is(summary):not(.active,.btn):focus-visible,:where(.menu li:not(.menu-title,.disabled)>:not(ul,details,.menu-title)):not(summary,.active,.btn).focus,:where(.menu li:not(.menu-title,.disabled)>:not(ul,details,.menu-title)):not(summary,.active,.btn):focus,:where(.menu li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):is(summary):not(.active,.btn):focus-visible,:where(.menu li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(summary,.active,.btn).focus,:where(.menu li:not(.menu-title,.disabled)>details>summary:not(.menu-title)):not(summary,.active,.btn):focus{background-color:var(--fallback-bc,oklch(var(--bc)/.1));cursor:pointer;--tw-text-opacity:1;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));outline:2px solid transparent;outline-offset:2px}.menu li>:not(ul,.menu-title,details,.btn).active,.menu li>:not(ul,.menu-title,details,.btn):active,.menu li>details>summary:active{--tw-bg-opacity:1;background-color:var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)))}.menu :where(li>details>summary)::-webkit-details-marker{display:none}.menu :where(li>.menu-dropdown-toggle):after,.menu :where(li>details>summary):after{box-shadow:2px 2px;content:"";display:block;height:.5rem;justify-self:end;margin-top:-.5rem;pointer-events:none;transform:rotate(45deg);transform-origin:75% 75%;transition-duration:.3s;transition-property:transform,margin-top;transition-timing-function:cubic-bezier(.4,0,.2,1);width:.5rem}.menu :where(li>.menu-dropdown-toggle.menu-dropdown-show):after,.menu :where(li>details[open]>summary):after{margin-top:0;transform:rotate(225deg)}.menu-title{color:var(--fallback-bc,oklch(var(--bc)/.4));font-size:.875rem;font-weight:700;line-height:1.25rem;padding:.5rem 1rem}.mockup-phone .camera{background:#000;border-bottom-left-radius:17px;border-bottom-right-radius:17px;height:25px;left:0;margin:0 auto;position:relative;top:0;width:150px;z-index:11}.mockup-phone .camera:before{background-color:#0c0b0e;border-radius:5px;content:"";height:4px;left:50%;position:absolute;top:35%;transform:translate(-50%,-50%);width:50px}.mockup-phone .camera:after{background-color:#0f0b25;border-radius:5px;content:"";height:8px;left:70%;position:absolute;top:20%;width:8px}.mockup-phone .display{border-radius:40px;margin-top:-25px;overflow:hidden}.mockup-browser .mockup-browser-toolbar .\!input{display:block!important;height:1.75rem!important;margin-left:auto!important;margin-right:auto!important;overflow:hidden!important;position:relative!important;text-overflow:ellipsis!important;white-space:nowrap!important;width:24rem!important;--tw-bg-opacity:1!important;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)))!important;direction:ltr!important;padding-left:2rem!important}.mockup-browser .mockup-browser-toolbar .input{display:block;height:1.75rem;margin-left:auto;margin-right:auto;overflow:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:24rem;--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));direction:ltr;padding-left:2rem}.mockup-browser .mockup-browser-toolbar .\!input:before{aspect-ratio:1/1!important;content:""!important;height:.75rem!important;left:.5rem!important;position:absolute!important;top:50%!important;--tw-translate-y:-50%!important;border-color:currentColor!important;border-radius:9999px!important;border-width:2px!important;opacity:.6!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.mockup-browser .mockup-browser-toolbar .input:before{aspect-ratio:1/1;content:"";height:.75rem;left:.5rem;position:absolute;top:50%;--tw-translate-y:-50%;border-color:currentColor;border-radius:9999px;border-width:2px;opacity:.6;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.mockup-browser .mockup-browser-toolbar .\!input:after{content:""!important;height:.5rem!important;left:1.25rem!important;position:absolute!important;top:50%!important;--tw-translate-y:25%!important;--tw-rotate:-45deg!important;border-color:currentColor!important;border-radius:9999px!important;border-width:1px!important;opacity:.6!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.mockup-browser .mockup-browser-toolbar .input:after{content:"";height:.5rem;left:1.25rem;position:absolute;top:50%;--tw-translate-y:25%;--tw-rotate:-45deg;border-color:currentColor;border-radius:9999px;border-width:1px;opacity:.6;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.modal::backdrop,.modal:not(dialog:not(.modal-open)){animation:modal-pop .2s ease-out;background-color:#0006}.\!modal::backdrop,.\!modal:not(dialog:not(.modal-open)){animation:modal-pop .2s ease-out!important;background-color:#0006!important}.modal-backdrop{align-self:stretch;color:transparent;display:grid;grid-column-start:1;grid-row-start:1;justify-self:stretch;z-index:-1}.modal-open .modal-box,.modal-toggle:checked+.modal .modal-box,.modal:target .modal-box,.modal[open] .modal-box{--tw-translate-y:0px;--tw-scale-x:1;--tw-scale-y:1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\!modal:target .modal-box,.\!modal[open] .modal-box,.modal-toggle:checked+.\!modal .modal-box{--tw-translate-y:0px!important;--tw-scale-x:1!important;--tw-scale-y:1!important;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))!important}.modal-action>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}@keyframes modal-pop{0%{opacity:0}}.progress::-moz-progress-bar{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)))}.progress-primary::-moz-progress-bar{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)))}.progress-secondary::-moz-progress-bar{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity)))}.progress-accent::-moz-progress-bar{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity)))}.progress-info::-moz-progress-bar{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)))}.progress-success::-moz-progress-bar{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)))}.progress-warning::-moz-progress-bar{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)))}.progress:indeterminate{--progress-color:var(--fallback-bc,oklch(var(--bc)/1));animation:progress-loading 5s ease-in-out infinite;background-image:repeating-linear-gradient(90deg,var(--progress-color) -1%,var(--progress-color) 10%,transparent 10%,transparent 90%);background-position-x:15%;background-size:200%}.progress-primary:indeterminate{--progress-color:var(--fallback-p,oklch(var(--p)/1))}.progress-secondary:indeterminate{--progress-color:var(--fallback-s,oklch(var(--s)/1))}.progress-accent:indeterminate{--progress-color:var(--fallback-a,oklch(var(--a)/1))}.progress-info:indeterminate{--progress-color:var(--fallback-in,oklch(var(--in)/1))}.progress-success:indeterminate{--progress-color:var(--fallback-su,oklch(var(--su)/1))}.progress-warning:indeterminate{--progress-color:var(--fallback-wa,oklch(var(--wa)/1))}.progress::-webkit-progress-bar{background-color:transparent;border-radius:var(--rounded-box,1rem)}.progress::-webkit-progress-value{border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)))}.progress-primary::-webkit-progress-value{--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)))}.progress-secondary::-webkit-progress-value{--tw-bg-opacity:1;background-color:var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity)))}.progress-accent::-webkit-progress-value{--tw-bg-opacity:1;background-color:var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity)))}.progress-info::-webkit-progress-value{--tw-bg-opacity:1;background-color:var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)))}.progress-success::-webkit-progress-value{--tw-bg-opacity:1;background-color:var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)))}.progress-warning::-webkit-progress-value{--tw-bg-opacity:1;background-color:var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)))}.progress:indeterminate::-moz-progress-bar{animation:progress-loading 5s ease-in-out infinite;background-color:transparent;background-image:repeating-linear-gradient(90deg,var(--progress-color) -1%,var(--progress-color) 10%,transparent 10%,transparent 90%);background-position-x:15%;background-size:200%}@keyframes progress-loading{50%{background-position-x:-115%}}.radio:focus{box-shadow:none}.radio:focus-visible{outline-color:var(--fallback-bc,oklch(var(--bc)/1));outline-offset:2px;outline-style:solid;outline-width:2px}.radio:checked,.radio[aria-checked=true]{--tw-bg-opacity:1;animation:radiomark var(--animation-input,.2s) ease-out;background-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));background-image:none;box-shadow:0 0 0 4px var(--fallback-b1,oklch(var(--b1)/1)) inset,0 0 0 4px var(--fallback-b1,oklch(var(--b1)/1)) inset}.radio-primary{--chkbg:var(--p);--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)))}.radio-primary:focus-visible{outline-color:var(--fallback-p,oklch(var(--p)/1))}.radio-primary:checked,.radio-primary[aria-checked=true]{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}.radio:disabled{cursor:not-allowed;opacity:.2}@keyframes radiomark{0%{box-shadow:0 0 0 12px var(--fallback-b1,oklch(var(--b1)/1)) inset,0 0 0 12px var(--fallback-b1,oklch(var(--b1)/1)) inset}50%{box-shadow:0 0 0 3px var(--fallback-b1,oklch(var(--b1)/1)) inset,0 0 0 3px var(--fallback-b1,oklch(var(--b1)/1)) inset}to{box-shadow:0 0 0 4px var(--fallback-b1,oklch(var(--b1)/1)) inset,0 0 0 4px var(--fallback-b1,oklch(var(--b1)/1)) inset}}.range:focus-visible::-webkit-slider-thumb{--focus-shadow:0 0 0 6px var(--fallback-b1,oklch(var(--b1)/1)) inset,0 0 0 2rem var(--range-shdw) inset}.range:focus-visible::-moz-range-thumb{--focus-shadow:0 0 0 6px var(--fallback-b1,oklch(var(--b1)/1)) inset,0 0 0 2rem var(--range-shdw) inset}.range::-webkit-slider-runnable-track{background-color:var(--fallback-bc,oklch(var(--bc)/.1));border-radius:var(--rounded-box,1rem);height:.5rem;width:100%}.range::-moz-range-track{background-color:var(--fallback-bc,oklch(var(--bc)/.1));border-radius:var(--rounded-box,1rem);height:.5rem;width:100%}.range::-webkit-slider-thumb{border-radius:var(--rounded-box,1rem);border-style:none;height:1.5rem;position:relative;width:1.5rem;--tw-bg-opacity:1;appearance:none;-webkit-appearance:none;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));color:var(--range-shdw);top:50%;transform:translateY(-50%);--filler-size:100rem;--filler-offset:0.6rem;box-shadow:0 0 0 3px var(--range-shdw) inset,var(--focus-shadow,0 0),calc(var(--filler-size)*-1 - var(--filler-offset)) 0 0 var(--filler-size)}.range::-moz-range-thumb{border-radius:var(--rounded-box,1rem);border-style:none;height:1.5rem;position:relative;width:1.5rem;--tw-bg-opacity:1;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));color:var(--range-shdw);top:50%;--filler-size:100rem;--filler-offset:0.5rem;box-shadow:0 0 0 3px var(--range-shdw) inset,var(--focus-shadow,0 0),calc(var(--filler-size)*-1 - var(--filler-offset)) 0 0 var(--filler-size)}.range-error{--range-shdw:var(--fallback-er,oklch(var(--er)/1))}@keyframes rating-pop{0%{transform:translateY(-.125em)}40%{transform:translateY(-.125em)}to{transform:translateY(0)}}.select-bordered,.select:focus{border-color:var(--fallback-bc,oklch(var(--bc)/.2))}.select:focus{box-shadow:none;outline-color:var(--fallback-bc,oklch(var(--bc)/.2));outline-offset:2px;outline-style:solid;outline-width:2px}.select-disabled,.select:disabled,.select[disabled]{cursor:not-allowed;--tw-border-opacity:1;border-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));--tw-text-opacity:0.2}.select-disabled::-moz-placeholder,.select:disabled::-moz-placeholder,.select[disabled]::-moz-placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.select-disabled::placeholder,.select:disabled::placeholder,.select[disabled]::placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.select-multiple,.select[multiple],.select[size].select:not([size="1"]){background-image:none;padding-right:1rem}[dir=rtl] .select{background-position:12px calc(1px + 50%),16px calc(1px + 50%)}@keyframes skeleton{0%{background-position:150%}to{background-position:-50%}}:where(.stats)>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;--tw-divide-y-reverse:0;border-width:calc(0px*(1 - var(--tw-divide-y-reverse))) calc(1px*var(--tw-divide-x-reverse)) calc(0px*var(--tw-divide-y-reverse)) calc(1px*(1 - var(--tw-divide-x-reverse)))}:is([dir=rtl] .stats>:not([hidden])~:not([hidden])){--tw-divide-x-reverse:1}.steps .step:before{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));content:"";height:.5rem;margin-inline-start:-100%;top:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));width:100%}.steps .step:after,.steps .step:before{grid-column-start:1;grid-row-start:1;--tw-bg-opacity:1;background-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)));--tw-text-opacity:1}.steps .step:after{border-radius:9999px;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));content:counter(step);counter-increment:step;display:grid;height:2rem;place-items:center;place-self:center;position:relative;width:2rem;z-index:1}.steps .step:first-child:before{content:none}.steps .step[data-content]:after{content:attr(data-content)}.steps .step-neutral+.step-neutral:before,.steps .step-neutral:after{--tw-bg-opacity:1;background-color:var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)))}.steps .step-primary+.step-primary:before,.steps .step-primary:after{--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}.steps .step-secondary+.step-secondary:before,.steps .step-secondary:after{--tw-bg-opacity:1;background-color:var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity)))}.steps .step-accent+.step-accent:before,.steps .step-accent:after{--tw-bg-opacity:1;background-color:var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity)))}.steps .step-info+.step-info:before,.steps .step-info:after{--tw-bg-opacity:1;background-color:var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)))}.steps .step-info:after{--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)))}.steps .step-success+.step-success:before,.steps .step-success:after{--tw-bg-opacity:1;background-color:var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)))}.steps .step-success:after{--tw-text-opacity:1;color:var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)))}.steps .step-warning+.step-warning:before,.steps .step-warning:after{--tw-bg-opacity:1;background-color:var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)))}.steps .step-warning:after{--tw-text-opacity:1;color:var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)))}.steps .step-error+.step-error:before,.steps .step-error:after{--tw-bg-opacity:1;background-color:var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity)))}.steps .step-error:after{--tw-text-opacity:1;color:var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)))}.tabs-lifted>.tab:focus-visible{border-end-end-radius:0;border-end-start-radius:0}.tab.tab-active:not(.tab-disabled):not([disabled]),.tab:is(input:checked){border-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));--tw-border-opacity:1;--tw-text-opacity:1}.tab:focus{outline:2px solid transparent;outline-offset:2px}.tab:focus-visible{outline:2px solid currentColor;outline-offset:-5px}.tab-disabled,.tab[disabled]{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));cursor:not-allowed;--tw-text-opacity:0.2}.tabs-bordered>.tab{border-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));--tw-border-opacity:0.2;border-bottom-width:calc(var(--tab-border, 1px) + 1px);border-style:solid}.tabs-lifted>.tab{border:var(--tab-border,1px) solid transparent;border-bottom-color:var(--tab-border-color);border-start-end-radius:var(--tab-radius,.5rem);border-start-start-radius:var(--tab-radius,.5rem);border-width:0 0 var(--tab-border,1px) 0;padding-inline-end:var(--tab-padding,1rem);padding-inline-start:var(--tab-padding,1rem);padding-top:var(--tab-border,1px)}.tabs-lifted>.tab.tab-active:not(.tab-disabled):not([disabled]),.tabs-lifted>.tab:is(input:checked){background-color:var(--tab-bg);border-inline-end-color:var(--tab-border-color);border-inline-start-color:var(--tab-border-color);border-top-color:var(--tab-border-color);border-width:var(--tab-border,1px) var(--tab-border,1px) 0 var(--tab-border,1px);padding-inline-end:calc(var(--tab-padding, 1rem) - var(--tab-border, 1px));padding-bottom:var(--tab-border,1px);padding-inline-start:calc(var(--tab-padding, 1rem) - var(--tab-border, 1px));padding-top:0}.tabs-lifted>.tab.tab-active:not(.tab-disabled):not([disabled]):before,.tabs-lifted>.tab:is(input:checked):before{background-position:0 0,100% 0;background-repeat:no-repeat;background-size:var(--tab-radius,.5rem);bottom:0;content:"";display:block;height:var(--tab-radius,.5rem);position:absolute;width:calc(100% + var(--tab-radius, .5rem)*2);z-index:1;--tab-grad:calc(69% - var(--tab-border, 1px));--radius-start:radial-gradient(circle at top left,transparent var(--tab-grad),var(--tab-border-color) calc(var(--tab-grad) + 0.25px),var(--tab-border-color) calc(var(--tab-grad) + var(--tab-border, 1px)),var(--tab-bg) calc(var(--tab-grad) + var(--tab-border, 1px) + 0.25px));--radius-end:radial-gradient(circle at top right,transparent var(--tab-grad),var(--tab-border-color) calc(var(--tab-grad) + 0.25px),var(--tab-border-color) calc(var(--tab-grad) + var(--tab-border, 1px)),var(--tab-bg) calc(var(--tab-grad) + var(--tab-border, 1px) + 0.25px));background-image:var(--radius-start),var(--radius-end)}.tabs-lifted>.tab.tab-active:not(.tab-disabled):not([disabled]):first-child:before,.tabs-lifted>.tab:is(input:checked):first-child:before{background-image:var(--radius-end);background-position:100% 0}[dir=rtl] .tabs-lifted>.tab.tab-active:not(.tab-disabled):not([disabled]):first-child:before,[dir=rtl] .tabs-lifted>.tab:is(input:checked):first-child:before{background-image:var(--radius-start);background-position:0 0}.tabs-lifted>.tab.tab-active:not(.tab-disabled):not([disabled]):last-child:before,.tabs-lifted>.tab:is(input:checked):last-child:before{background-image:var(--radius-start);background-position:0 0}[dir=rtl] .tabs-lifted>.tab.tab-active:not(.tab-disabled):not([disabled]):last-child:before,[dir=rtl] .tabs-lifted>.tab:is(input:checked):last-child:before{background-image:var(--radius-end);background-position:100% 0}.tabs-lifted>.tab-active:not(.tab-disabled):not([disabled])+.tabs-lifted .tab-active:not(.tab-disabled):not([disabled]):before,.tabs-lifted>.tab:is(input:checked)+.tabs-lifted .tab:is(input:checked):before{background-image:var(--radius-end);background-position:100% 0}.tabs-boxed{--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));padding:.25rem}.tabs-boxed,.tabs-boxed .tab{border-radius:var(--rounded-btn,.5rem)}.tabs-boxed .tab-active:not(.tab-disabled):not([disabled]),.tabs-boxed :is(input:checked){--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}:is([dir=rtl] .table){text-align:right}.table :where(th,td){padding:.75rem 1rem;vertical-align:middle}.table tr.active,.table tr.active:nth-child(2n),.table-zebra tbody tr:nth-child(2n){--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)))}.table-zebra tr.active,.table-zebra tr.active:nth-child(2n),.table-zebra-zebra tbody tr:nth-child(2n){--tw-bg-opacity:1;background-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)))}.table :where(thead,tbody) :where(tr:first-child:last-child),.table :where(thead,tbody) :where(tr:not(:last-child)){border-bottom-width:1px;--tw-border-opacity:1;border-bottom-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)))}.table :where(thead,tfoot){color:var(--fallback-bc,oklch(var(--bc)/.6));font-size:.75rem;font-weight:700;line-height:1rem;white-space:nowrap}.textarea-bordered,.textarea:focus{border-color:var(--fallback-bc,oklch(var(--bc)/.2))}.textarea:focus{box-shadow:none;outline-color:var(--fallback-bc,oklch(var(--bc)/.2));outline-offset:2px;outline-style:solid;outline-width:2px}.textarea-disabled,.textarea:disabled,.textarea[disabled]{cursor:not-allowed;--tw-border-opacity:1;border-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));--tw-text-opacity:0.2}.textarea-disabled::-moz-placeholder,.textarea:disabled::-moz-placeholder,.textarea[disabled]::-moz-placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.textarea-disabled::placeholder,.textarea:disabled::placeholder,.textarea[disabled]::placeholder{color:var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));--tw-placeholder-opacity:0.2}.timeline hr{height:.25rem}:where(.timeline hr){--tw-bg-opacity:1;background-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)))}:where(.timeline:has(.timeline-middle) hr):first-child{border-end-end-radius:var(--rounded-badge,1.9rem);border-end-start-radius:0;border-start-end-radius:var(--rounded-badge,1.9rem);border-start-start-radius:0}:where(.timeline:has(.timeline-middle) hr):last-child{border-end-end-radius:0;border-end-start-radius:var(--rounded-badge,1.9rem);border-start-end-radius:0;border-start-start-radius:var(--rounded-badge,1.9rem)}:where(.timeline:not(:has(.timeline-middle)) :first-child hr:last-child){border-end-end-radius:0;border-end-start-radius:var(--rounded-badge,1.9rem);border-start-end-radius:0;border-start-start-radius:var(--rounded-badge,1.9rem)}:where(.timeline:not(:has(.timeline-middle)) :last-child hr:first-child){border-end-end-radius:var(--rounded-badge,1.9rem);border-end-start-radius:0;border-start-end-radius:var(--rounded-badge,1.9rem);border-start-start-radius:0}.timeline-box{border-radius:var(--rounded-box,1rem);border-width:1px;--tw-border-opacity:1;border-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity)));--tw-bg-opacity:1;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));padding:.5rem 1rem;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.toast>*{animation:toast-pop .25s ease-out}@keyframes toast-pop{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}[dir=rtl] .toggle{--handleoffsetcalculator:calc(var(--handleoffset)*1)}.toggle:focus-visible{outline-color:var(--fallback-bc,oklch(var(--bc)/.2));outline-offset:2px;outline-style:solid;outline-width:2px}.toggle:hover{background-color:currentColor}.toggle:checked,.toggle[aria-checked=true],.toggle[checked=true]{background-image:none;--handleoffsetcalculator:var(--handleoffset);--tw-text-opacity:1;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)))}[dir=rtl] .toggle:checked,[dir=rtl] .toggle[aria-checked=true],[dir=rtl] .toggle[checked=true]{--handleoffsetcalculator:calc(var(--handleoffset)*-1)}.toggle:indeterminate{--tw-text-opacity:1;box-shadow:calc(var(--handleoffset)/2) 0 0 2px var(--tglbg) inset,calc(var(--handleoffset)/-2) 0 0 2px var(--tglbg) inset,0 0 0 2px var(--tglbg) inset;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)))}[dir=rtl] .toggle:indeterminate{box-shadow:calc(var(--handleoffset)/2) 0 0 2px var(--tglbg) inset,calc(var(--handleoffset)/-2) 0 0 2px var(--tglbg) inset,0 0 0 2px var(--tglbg) inset}.toggle-primary:focus-visible{outline-color:var(--fallback-p,oklch(var(--p)/1))}.toggle-primary:checked,.toggle-primary[aria-checked=true],.toggle-primary[checked=true]{border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));--tw-border-opacity:0.1;--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)))}.toggle-success:focus-visible{outline-color:var(--fallback-su,oklch(var(--su)/1))}.toggle-success:checked,.toggle-success[aria-checked=true],.toggle-success[checked=true]{border-color:var(--fallback-su,oklch(var(--su)/var(--tw-border-opacity)));--tw-border-opacity:0.1;--tw-bg-opacity:1;background-color:var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)))}.toggle-warning:focus-visible{outline-color:var(--fallback-wa,oklch(var(--wa)/1))}.toggle-warning:checked,.toggle-warning[aria-checked=true],.toggle-warning[checked=true]{border-color:var(--fallback-wa,oklch(var(--wa)/var(--tw-border-opacity)));--tw-border-opacity:0.1;--tw-bg-opacity:1;background-color:var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)))}.toggle-error:focus-visible{outline-color:var(--fallback-er,oklch(var(--er)/1))}.toggle-error:checked,.toggle-error[aria-checked=true],.toggle-error[checked=true]{border-color:var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity)));--tw-border-opacity:0.1;--tw-bg-opacity:1;background-color:var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity)));--tw-text-opacity:1;color:var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)))}.toggle:disabled{cursor:not-allowed;--tw-border-opacity:1;background-color:transparent;border-color:var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));opacity:.3;--togglehandleborder:0 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset,var(--handleoffsetcalculator) 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset}.glass,.glass.btn-active{-webkit-backdrop-filter:blur(var(--glass-blur,40px));backdrop-filter:blur(var(--glass-blur,40px));background-color:transparent;background-image:linear-gradient(135deg,rgb(255 255 255/var(--glass-opacity,30%)) 0,transparent 100%),linear-gradient(var(--glass-reflex-degree,100deg),rgb(255 255 255/var(--glass-reflex-opacity,10%)) 25%,transparent 25%);border:none;box-shadow:0 0 0 1px rgb(255 255 255/var(--glass-border-opacity,10%)) inset,0 0 0 2px rgb(0 0 0/5%);text-shadow:0 1px rgb(0 0 0/var(--glass-text-shadow-opacity,5%))}@media (hover:hover){.glass.btn-active{-webkit-backdrop-filter:blur(var(--glass-blur,40px));backdrop-filter:blur(var(--glass-blur,40px));background-color:transparent;background-image:linear-gradient(135deg,rgb(255 255 255/var(--glass-opacity,30%)) 0,transparent 100%),linear-gradient(var(--glass-reflex-degree,100deg),rgb(255 255 255/var(--glass-reflex-opacity,10%)) 25%,transparent 25%);border:none;box-shadow:0 0 0 1px rgb(255 255 255/var(--glass-border-opacity,10%)) inset,0 0 0 2px rgb(0 0 0/5%);text-shadow:0 1px rgb(0 0 0/var(--glass-text-shadow-opacity,5%))}}.artboard.phone-1.artboard-horizontal,.artboard.phone-1.horizontal{height:320px;width:568px}.artboard.phone-2.artboard-horizontal,.artboard.phone-2.horizontal{height:375px;width:667px}.artboard.phone-3.artboard-horizontal,.artboard.phone-3.horizontal{height:414px;width:736px}.artboard.phone-4.artboard-horizontal,.artboard.phone-4.horizontal{height:375px;width:812px}.artboard.phone-5.artboard-horizontal,.artboard.phone-5.horizontal{height:414px;width:896px}.artboard.phone-6.artboard-horizontal,.artboard.phone-6.horizontal{height:320px;width:1024px}.badge-xs{font-size:.75rem;height:.75rem;line-height:.75rem;padding-left:.313rem;padding-right:.313rem}.badge-sm{font-size:.75rem;height:1rem;line-height:1rem;padding-left:.438rem;padding-right:.438rem}.badge-lg{font-size:1rem;height:1.5rem;line-height:1.5rem;padding-left:.688rem;padding-right:.688rem}.btm-nav-xs>:where(.active){border-top-width:1px}.btm-nav-sm>:where(.active){border-top-width:2px}.btm-nav-md>:where(.active){border-top-width:2px}.btm-nav-lg>:where(.active){border-top-width:4px}.btn-xs{font-size:.75rem;height:1.5rem;min-height:1.5rem;padding-left:.5rem;padding-right:.5rem}.btn-sm{font-size:.875rem;height:2rem;min-height:2rem;padding-left:.75rem;padding-right:.75rem}.btn-lg{font-size:1.125rem;height:4rem;min-height:4rem;padding-left:1.5rem;padding-right:1.5rem}.btn-wide{width:16rem}.btn-block{width:100%}.btn-square:where(.btn-xs){height:1.5rem;padding:0;width:1.5rem}.btn-square:where(.btn-sm){height:2rem;padding:0;width:2rem}.btn-square:where(.btn-lg){height:4rem;padding:0;width:4rem}.btn-circle:where(.btn-xs){border-radius:9999px;height:1.5rem;padding:0;width:1.5rem}.btn-circle:where(.btn-sm){border-radius:9999px;height:2rem;padding:0;width:2rem}.btn-circle:where(.btn-md){border-radius:9999px;height:3rem;padding:0;width:3rem}.btn-circle:where(.btn-lg){border-radius:9999px;height:4rem;padding:0;width:4rem}[type=checkbox].checkbox-xs{height:1rem;width:1rem}[type=checkbox].checkbox-sm{height:1.25rem;width:1.25rem}.indicator :where(.indicator-item){bottom:auto;inset-inline-end:0;inset-inline-start:auto;top:0;--tw-translate-y:-50%;--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}:is([dir=rtl] .indicator :where(.indicator-item)){--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.indicator :where(.indicator-item.indicator-start){inset-inline-end:auto;inset-inline-start:0;--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}:is([dir=rtl] .indicator :where(.indicator-item.indicator-start)){--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.indicator :where(.indicator-item.indicator-center){inset-inline-end:50%;inset-inline-start:50%;--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}:is([dir=rtl] .indicator :where(.indicator-item.indicator-center)){--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.indicator :where(.indicator-item.indicator-end){inset-inline-end:0;inset-inline-start:auto;--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}:is([dir=rtl] .indicator :where(.indicator-item.indicator-end)){--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.indicator :where(.indicator-item.indicator-bottom){bottom:0;top:auto;--tw-translate-y:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.indicator :where(.indicator-item.indicator-middle){bottom:50%;top:50%;--tw-translate-y:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.indicator :where(.indicator-item.indicator-top){bottom:auto;top:0;--tw-translate-y:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.input-sm{font-size:.875rem;height:2rem;line-height:2rem;padding-left:.75rem;padding-right:.75rem}.join.join-vertical{flex-direction:column}.join.join-vertical .join-item:first-child:not(:last-child),.join.join-vertical :first-child:not(:last-child) .join-item{border-end-end-radius:0;border-end-start-radius:0;border-start-end-radius:inherit;border-start-start-radius:inherit}.join.join-vertical .join-item:last-child:not(:first-child),.join.join-vertical :last-child:not(:first-child) .join-item{border-end-end-radius:inherit;border-end-start-radius:inherit;border-start-end-radius:0;border-start-start-radius:0}.join.join-horizontal{flex-direction:row}.join.join-horizontal .join-item:first-child:not(:last-child),.join.join-horizontal :first-child:not(:last-child) .join-item{border-end-end-radius:0;border-end-start-radius:inherit;border-start-end-radius:0;border-start-start-radius:inherit}.join.join-horizontal .join-item:last-child:not(:first-child),.join.join-horizontal :last-child:not(:first-child) .join-item{border-end-end-radius:inherit;border-end-start-radius:0;border-start-end-radius:inherit;border-start-start-radius:0}.menu-horizontal{display:inline-flex;flex-direction:row}.menu-horizontal>li:not(.menu-title)>details>ul{position:absolute}[type=radio].radio-sm{height:1.25rem;width:1.25rem}.range-xs{height:1rem}.range-xs::-webkit-slider-runnable-track{height:.25rem}.range-xs::-moz-range-track{height:.25rem}.range-xs::-webkit-slider-thumb{height:1rem;width:1rem;--filler-offset:0.4rem}.range-xs::-moz-range-thumb{height:1rem;width:1rem;--filler-offset:0.4rem}.range-sm{height:1.25rem}.range-sm::-webkit-slider-runnable-track{height:.25rem}.range-sm::-moz-range-track{height:.25rem}.range-sm::-webkit-slider-thumb{height:1.25rem;width:1.25rem;--filler-offset:0.5rem}.range-sm::-moz-range-thumb{height:1.25rem;width:1.25rem;--filler-offset:0.5rem}.select-xs{font-size:.75rem;height:1.5rem;line-height:1rem;line-height:1.625;min-height:1.5rem;padding-left:.5rem;padding-right:2rem}[dir=rtl] .select-xs{padding-left:2rem;padding-right:.5rem}.stats-vertical{grid-auto-flow:row}.steps-horizontal .step{display:grid;grid-template-columns:repeat(1,minmax(0,1fr));grid-template-rows:repeat(2,minmax(0,1fr));place-items:center;text-align:center}.steps-vertical .step{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:repeat(1,minmax(0,1fr))}.tabs-md :where(.tab){font-size:.875rem;height:2rem;line-height:1.25rem;line-height:2;--tab-padding:1rem}.tabs-lg :where(.tab){font-size:1.125rem;height:3rem;line-height:1.75rem;line-height:2;--tab-padding:1.25rem}.tabs-sm :where(.tab){font-size:.875rem;height:1.5rem;line-height:.75rem;--tab-padding:0.75rem}.tabs-xs :where(.tab){font-size:.75rem;height:1.25rem;line-height:.75rem;--tab-padding:0.5rem}.timeline-vertical{flex-direction:column}.timeline-compact .timeline-start,.timeline-horizontal.timeline-compact .timeline-start{align-self:flex-start;grid-column-end:4;grid-column-start:1;grid-row-end:4;grid-row-start:3;justify-self:center;margin:.25rem}.timeline-compact li:has(.timeline-start) .timeline-end,.timeline-horizontal.timeline-compact li:has(.timeline-start) .timeline-end{grid-column-start:none;grid-row-start:auto}.timeline-vertical.timeline-compact>li{--timeline-col-start:0}.timeline-vertical.timeline-compact .timeline-start{align-self:center;grid-column-end:4;grid-column-start:3;grid-row-end:4;grid-row-start:1;justify-self:start}.timeline-vertical.timeline-compact li:has(.timeline-start) .timeline-end{grid-column-start:auto;grid-row-start:none}:where(.timeline-vertical>li){--timeline-row-start:minmax(0,1fr);--timeline-row-end:minmax(0,1fr);justify-items:center}.timeline-vertical>li>hr{height:100%}:where(.timeline-vertical>li>hr):first-child{grid-column-start:2;grid-row-start:1}:where(.timeline-vertical>li>hr):last-child{grid-column-end:auto;grid-column-start:2;grid-row-end:none;grid-row-start:3}.timeline-vertical .timeline-start{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:4;grid-row-start:1;justify-self:end}.timeline-vertical .timeline-end{align-self:center;grid-column-end:4;grid-column-start:3;grid-row-end:4;grid-row-start:1;justify-self:start}.timeline-vertical:where(.timeline-snap-icon)>li{--timeline-col-start:minmax(0,1fr);--timeline-row-start:0.5rem}.timeline-horizontal .timeline-start{align-self:flex-end;grid-column-end:4;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:center}.timeline-horizontal .timeline-end{align-self:flex-start;grid-column-end:4;grid-column-start:1;grid-row-end:4;grid-row-start:3;justify-self:center}.timeline-horizontal:where(.timeline-snap-icon)>li,:where(.timeline-snap-icon)>li{--timeline-col-start:0.5rem;--timeline-row-start:minmax(0,1fr)}:where(.toast){bottom:0;inset-inline-end:0;inset-inline-start:auto;top:auto;--tw-translate-x:0px;--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.toast:where(.toast-start){inset-inline-end:auto;inset-inline-start:0;--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.toast:where(.toast-center){inset-inline-end:50%;inset-inline-start:50%;--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}:is([dir=rtl] .toast:where(.toast-center)){--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.toast:where(.toast-end){inset-inline-end:0;inset-inline-start:auto;--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.toast:where(.toast-bottom){bottom:0;top:auto;--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.toast:where(.toast-middle){bottom:auto;top:50%;--tw-translate-y:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.toast:where(.toast-top){bottom:auto;top:0;--tw-translate-y:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}[type=checkbox].toggle-sm{--handleoffset:0.75rem;height:1.25rem;width:2rem}.tooltip{--tooltip-offset:calc(100% + 1px + var(--tooltip-tail, 0px))}.tooltip:before{content:var(--tw-content);pointer-events:none;position:absolute;z-index:1;--tw-content:attr(data-tip)}.tooltip-top:before,.tooltip:before{bottom:var(--tooltip-offset);left:50%;right:auto;top:auto;transform:translateX(-50%)}.tooltip-bottom:before{bottom:auto;left:50%;right:auto;top:var(--tooltip-offset);transform:translateX(-50%)}.tooltip-left:before{left:auto;right:var(--tooltip-offset)}.tooltip-left:before,.tooltip-right:before{bottom:auto;top:50%;transform:translateY(-50%)}.tooltip-right:before{left:var(--tooltip-offset);right:auto}.avatar.online:before{background-color:var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)))}.avatar.offline:before,.avatar.online:before{border-radius:9999px;content:"";display:block;position:absolute;z-index:10;--tw-bg-opacity:1;height:15%;outline-color:var(--fallback-b1,oklch(var(--b1)/1));outline-style:solid;outline-width:2px;right:7%;top:7%;width:15%}.avatar.offline:before{background-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)))}.card-compact .card-body{font-size:.875rem;line-height:1.25rem;padding:1rem}.card-compact .card-title{margin-bottom:.25rem}.card-normal .card-body{font-size:1rem;line-height:1.5rem;padding:var(--padding-card,2rem)}.card-normal .card-title{margin-bottom:.75rem}.join.join-vertical>:where(:not(:first-child)){margin-left:0;margin-right:0;margin-top:-1px}.join.join-horizontal>:where(:not(:first-child)){margin-bottom:0;margin-top:0;margin-inline-start:-1px}.menu-horizontal>li:not(.menu-title)>details>ul{margin-inline-start:0;margin-top:1rem;padding-bottom:.5rem;padding-inline-end:.5rem;padding-top:.5rem}.menu-horizontal>li>details>ul:before{content:none}:where(.menu-horizontal>li:not(.menu-title)>details>ul){border-radius:var(--rounded-box,1rem);--tw-bg-opacity:1;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.menu-xs .menu-title{padding:.25rem .5rem}.menu-sm :where(li:not(.menu-title)>:not(ul,details,.menu-title)),.menu-sm :where(li:not(.menu-title)>details>summary:not(.menu-title)){border-radius:var(--rounded-btn,.5rem);font-size:.875rem;line-height:1.25rem;padding:.25rem .75rem}.menu-sm .menu-title{padding:.5rem .75rem}.menu-md .menu-title{padding:.5rem 1rem}.menu-lg .menu-title{padding:.75rem 1.5rem}.modal-top :where(.modal-box){max-width:none;width:100%;--tw-translate-y:-2.5rem;--tw-scale-x:1;--tw-scale-y:1;border-bottom-left-radius:var(--rounded-box,1rem);border-bottom-right-radius:var(--rounded-box,1rem);border-top-left-radius:0;border-top-right-radius:0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.modal-middle :where(.modal-box){max-width:32rem;width:91.666667%;--tw-translate-y:0px;--tw-scale-x:.9;--tw-scale-y:.9;border-bottom-left-radius:var(--rounded-box,1rem);border-bottom-right-radius:var(--rounded-box,1rem);border-top-left-radius:var(--rounded-box,1rem);border-top-right-radius:var(--rounded-box,1rem);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.modal-bottom :where(.modal-box){max-width:none;width:100%;--tw-translate-y:2.5rem;--tw-scale-x:1;--tw-scale-y:1;border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:var(--rounded-box,1rem);border-top-right-radius:var(--rounded-box,1rem);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.stats-vertical>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;--tw-divide-y-reverse:0;border-width:calc(1px*(1 - var(--tw-divide-y-reverse))) calc(0px*var(--tw-divide-x-reverse)) calc(1px*var(--tw-divide-y-reverse)) calc(0px*(1 - var(--tw-divide-x-reverse)))}.stats-vertical{overflow-y:auto}.steps-horizontal .step{grid-template-columns:auto;grid-template-rows:40px 1fr;min-width:4rem}.steps-horizontal .step:before{height:.5rem;width:100%;--tw-translate-x:0px;--tw-translate-y:0px;content:"";margin-inline-start:-100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}:is([dir=rtl] .steps-horizontal .step):before{--tw-translate-x:0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.steps-vertical .step{gap:.5rem;grid-template-columns:40px 1fr;grid-template-rows:auto;justify-items:start;min-height:4rem}.steps-vertical .step:before{height:100%;width:.5rem;--tw-translate-x:-50%;--tw-translate-y:-50%;margin-inline-start:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}:is([dir=rtl] .steps-vertical .step):before{--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.timeline-vertical>li>hr{width:.25rem}:where(.timeline-vertical:has(.timeline-middle)>li>hr):first-child{border-bottom-left-radius:var(--rounded-badge,1.9rem);border-bottom-right-radius:var(--rounded-badge,1.9rem);border-top-left-radius:0;border-top-right-radius:0}:where(.timeline-vertical:has(.timeline-middle)>li>hr):last-child{border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:var(--rounded-badge,1.9rem);border-top-right-radius:var(--rounded-badge,1.9rem)}:where(.timeline-vertical:not(:has(.timeline-middle)) :first-child>hr:last-child){border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:var(--rounded-badge,1.9rem);border-top-right-radius:var(--rounded-badge,1.9rem)}:where(.timeline-vertical:not(:has(.timeline-middle)) :last-child>hr:first-child){border-bottom-left-radius:var(--rounded-badge,1.9rem);border-bottom-right-radius:var(--rounded-badge,1.9rem);border-top-left-radius:0;border-top-right-radius:0}:where(.timeline-horizontal:has(.timeline-middle)>li>hr):first-child{border-end-end-radius:var(--rounded-badge,1.9rem);border-end-start-radius:0;border-start-end-radius:var(--rounded-badge,1.9rem);border-start-start-radius:0}:where(.timeline-horizontal:has(.timeline-middle)>li>hr):last-child{border-end-end-radius:0;border-end-start-radius:var(--rounded-badge,1.9rem);border-start-end-radius:0;border-start-start-radius:var(--rounded-badge,1.9rem)}.tooltip{display:inline-block;position:relative;text-align:center;--tooltip-tail:0.1875rem;--tooltip-color:var(--fallback-n,oklch(var(--n)/1));--tooltip-text-color:var(--fallback-nc,oklch(var(--nc)/1));--tooltip-tail-offset:calc(100% + 0.0625rem - var(--tooltip-tail))}.tooltip:after,.tooltip:before{opacity:0;transition-delay:.1s;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.tooltip:after{border-style:solid;border-width:var(--tooltip-tail,0);content:"";display:block;height:0;position:absolute;width:0}.tooltip:before{background-color:var(--tooltip-color);border-radius:.25rem;color:var(--tooltip-text-color);font-size:.875rem;line-height:1.25rem;max-width:20rem;padding:.25rem .5rem;width:-moz-max-content;width:max-content}.tooltip.tooltip-open:after,.tooltip.tooltip-open:before,.tooltip:hover:after,.tooltip:hover:before{opacity:1;transition-delay:75ms}.tooltip:has(:focus-visible):after,.tooltip:has(:focus-visible):before{opacity:1;transition-delay:75ms}.tooltip:not([data-tip]):hover:after,.tooltip:not([data-tip]):hover:before{opacity:0;visibility:hidden}.tooltip-top:after,.tooltip:after{border-color:var(--tooltip-color) transparent transparent transparent;bottom:var(--tooltip-tail-offset);left:50%;right:auto;top:auto;transform:translateX(-50%)}.tooltip-bottom:after{border-color:transparent transparent var(--tooltip-color) transparent;bottom:auto;left:50%;right:auto;top:var(--tooltip-tail-offset);transform:translateX(-50%)}.tooltip-left:after{border-color:transparent transparent transparent var(--tooltip-color);left:auto;right:calc(var(--tooltip-tail-offset) + .0625rem)}.tooltip-left:after,.tooltip-right:after{bottom:auto;top:50%;transform:translateY(-50%)}.tooltip-right:after{border-color:transparent var(--tooltip-color) transparent transparent;left:calc(var(--tooltip-tail-offset) + .0625rem);right:auto}.fade-out{opacity:0;transition:opacity .15s ease-in-out}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.left-2{left:.5rem}.left-4{left:1rem}.right-0{right:0}.right-2{right:.5rem}.right-3{right:.75rem}.right-5{right:1.25rem}.top-0{top:0}.top-16{top:4rem}.top-2{top:.5rem}.top-3{top:.75rem}.top-4{top:1rem}.top-5{top:1.25rem}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[10000\]{z-index:10000}.z-\[1\]{z-index:1}.z-\[6000\]{z-index:6000}.z-\[9999\]{z-index:9999}.col-span-2{grid-column:span 2/span 2}.m-0{margin:0}.m-5{margin:1.25rem}.m-auto{margin:auto}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-10{margin-bottom:2.5rem;margin-top:2.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-3{margin-bottom:.75rem;margin-top:.75rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-5{margin-bottom:1.25rem;margin-top:1.25rem}.mb-1{margin-bottom:.25rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-10{margin-left:2.5rem}.ml-14{margin-left:3.5rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-8{margin-left:2rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-40{height:10rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-96{height:24rem}.h-\[250px\]{height:250px}.h-\[25rem\]{height:25rem}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-96{max-height:24rem}.max-h-full{max-height:100%}.min-h-0{min-height:0}.min-h-80{min-height:20rem}.min-h-\[4rem\]{min-height:4rem}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-10{width:2.5rem}.w-10\/12{width:83.333333%}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\/3{width:66.666667%}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-4\/12{width:33.333333%}.w-40{width:10rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-52{width:13rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-80{width:20rem}.w-96{width:24rem}.w-auto{width:auto}.w-full{width:100%}.min-w-0{min-width:0}.min-w-52{min-width:13rem}.min-w-fit{min-width:-moz-fit-content;min-width:fit-content}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-screen-2xl{max-width:1536px}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.border-collapse{border-collapse:collapse}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.animate-\[supporter-rainbow-glow_8s_linear_infinite\]{animation:supporter-rainbow-glow 8s linear infinite}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-2{row-gap:.5rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.5rem*var(--tw-space-y-reverse));margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(2rem*var(--tw-space-y-reverse));margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-base-300>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-divide-opacity,1)))}.justify-self-end{justify-self:end}.justify-self-center{justify-self:center}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;white-space:nowrap}.text-ellipsis,.truncate{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-box{border-radius:var(--rounded-box,1rem)}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.rounded-b{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.rounded-t-none{border-top-left-radius:0;border-top-right-radius:0}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-base-300{--tw-border-opacity:1;border-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity,1)))}.border-base-content\/20{border-color:var(--fallback-bc,oklch(var(--bc)/.2))}.border-base-content\/50{border-color:var(--fallback-bc,oklch(var(--bc)/.5))}.border-blue-300{--tw-border-opacity:1;border-color:rgb(147 197 253/var(--tw-border-opacity,1))}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-error{--tw-border-opacity:1;border-color:var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity,1)))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-info\/20{border-color:var(--fallback-in,oklch(var(--in)/.2))}.border-neutral{--tw-border-opacity:1;border-color:var(--fallback-n,oklch(var(--n)/var(--tw-border-opacity,1)))}.border-primary{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity,1)))}.border-red-300{--tw-border-opacity:1;border-color:rgb(252 165 165/var(--tw-border-opacity,1))}.border-secondary\/20{border-color:var(--fallback-s,oklch(var(--s)/.2))}.border-sky-500{--tw-border-opacity:1;border-color:rgb(14 165 233/var(--tw-border-opacity,1))}.border-success\/20{border-color:var(--fallback-su,oklch(var(--su)/.2))}.border-transparent{border-color:transparent}.border-warning\/20{border-color:var(--fallback-wa,oklch(var(--wa)/.2))}.border-warning\/30{border-color:var(--fallback-wa,oklch(var(--wa)/.3))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.border-opacity-20{--tw-border-opacity:0.2}.bg-base-100{--tw-bg-opacity:1;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity,1)))}.bg-base-200{--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity,1)))}.bg-base-300{--tw-bg-opacity:1;background-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity,1)))}.bg-base-300\/30{background-color:var(--fallback-b3,oklch(var(--b3)/.3))}.bg-base-content\/30{background-color:var(--fallback-bc,oklch(var(--bc)/.3))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-blue-900{--tw-bg-opacity:1;background-color:rgb(30 58 138/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-info{--tw-bg-opacity:1;background-color:var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity,1)))}.bg-info\/10{background-color:var(--fallback-in,oklch(var(--in)/.1))}.bg-neutral{--tw-bg-opacity:1;background-color:var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity,1)))}.bg-primary{--tw-bg-opacity:1;background-color:var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity,1)))}.bg-primary\/10{background-color:var(--fallback-p,oklch(var(--p)/.1))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-secondary{--tw-bg-opacity:1;background-color:var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity,1)))}.bg-secondary-content{--tw-bg-opacity:1;background-color:var(--fallback-sc,oklch(var(--sc)/var(--tw-bg-opacity,1)))}.bg-secondary\/10{background-color:var(--fallback-s,oklch(var(--s)/.1))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.bg-success{--tw-bg-opacity:1;background-color:var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity,1)))}.bg-success\/10{background-color:var(--fallback-su,oklch(var(--su)/.1))}.bg-success\/30{background-color:var(--fallback-su,oklch(var(--su)/.3))}.bg-success\/50{background-color:var(--fallback-su,oklch(var(--su)/.5))}.bg-success\/70{background-color:var(--fallback-su,oklch(var(--su)/.7))}.bg-warning{--tw-bg-opacity:1;background-color:var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity,1)))}.bg-warning\/10{background-color:var(--fallback-wa,oklch(var(--wa)/.1))}.bg-warning\/20{background-color:var(--fallback-wa,oklch(var(--wa)/.2))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-opacity-10{--tw-bg-opacity:0.1}.bg-opacity-20{--tw-bg-opacity:0.2}.bg-opacity-60{--tw-bg-opacity:0.6}.bg-opacity-80{--tw-bg-opacity:0.8}.bg-gradient-to-bl{background-image:linear-gradient(to bottom left,var(--tw-gradient-stops))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-tl{background-image:linear-gradient(to top left,var(--tw-gradient-stops))}.bg-gradient-to-tr{background-image:linear-gradient(to top right,var(--tw-gradient-stops))}.from-base-100{--tw-gradient-from:var(--fallback-b1,oklch(var(--b1)/1)) var(--tw-gradient-from-position);--tw-gradient-to:var(--fallback-b1,oklch(var(--b1)/0)) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-blue-500{--tw-gradient-from:#3b82f6 var(--tw-gradient-from-position);--tw-gradient-to:rgba(59,130,246,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-blue-600{--tw-gradient-from:#2563eb var(--tw-gradient-from-position);--tw-gradient-to:rgba(37,99,235,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-green-400{--tw-gradient-from:#4ade80 var(--tw-gradient-from-position);--tw-gradient-to:rgba(74,222,128,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-green-500{--tw-gradient-from:#22c55e var(--tw-gradient-from-position);--tw-gradient-to:rgba(34,197,94,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-orange-400{--tw-gradient-from:#fb923c var(--tw-gradient-from-position);--tw-gradient-to:rgba(251,146,60,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-orange-600{--tw-gradient-from:#ea580c var(--tw-gradient-from-position);--tw-gradient-to:rgba(234,88,12,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-primary{--tw-gradient-from:var(--fallback-p,oklch(var(--p)/1)) var(--tw-gradient-from-position);--tw-gradient-to:var(--fallback-p,oklch(var(--p)/0)) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-red-400{--tw-gradient-from:#f87171 var(--tw-gradient-from-position);--tw-gradient-to:hsla(0,91%,71%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-red-800{--tw-gradient-from:#991b1b var(--tw-gradient-from-position);--tw-gradient-to:rgba(153,27,27,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-yellow-400{--tw-gradient-from:#facc15 var(--tw-gradient-from-position);--tw-gradient-to:rgba(250,204,21,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-yellow-700{--tw-gradient-from:#a16207 var(--tw-gradient-from-position);--tw-gradient-to:rgba(161,98,7,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-base-200{--tw-gradient-to:var(--fallback-b2,oklch(var(--b2)/1)) var(--tw-gradient-to-position)}.to-blue-700{--tw-gradient-to:#1d4ed8 var(--tw-gradient-to-position)}.to-blue-800{--tw-gradient-to:#1e40af var(--tw-gradient-to-position)}.to-green-700{--tw-gradient-to:#15803d var(--tw-gradient-to-position)}.to-orange-600{--tw-gradient-to:#ea580c var(--tw-gradient-to-position)}.to-orange-700{--tw-gradient-to:#c2410c var(--tw-gradient-to-position)}.to-purple-600{--tw-gradient-to:#9333ea var(--tw-gradient-to-position)}.to-red-400{--tw-gradient-to:#f87171 var(--tw-gradient-to-position)}.to-red-600{--tw-gradient-to:#dc2626 var(--tw-gradient-to-position)}.to-red-900{--tw-gradient-to:#7f1d1d var(--tw-gradient-to-position)}.to-secondary{--tw-gradient-to:var(--fallback-s,oklch(var(--s)/1)) var(--tw-gradient-to-position)}.to-yellow-400{--tw-gradient-to:#facc15 var(--tw-gradient-to-position)}.to-yellow-600{--tw-gradient-to:#ca8a04 var(--tw-gradient-to-position)}.stroke-current{stroke:currentColor}.stroke-info{stroke:var(--fallback-in,oklch(var(--in)/1))}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-12{padding-bottom:3rem;padding-top:3rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-20{padding-bottom:5rem;padding-top:5rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-5{padding-bottom:1.25rem;padding-top:1.25rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.py-8{padding-bottom:2rem;padding-top:2rem}.pb-2{padding-bottom:.5rem}.pl-0{padding-left:0}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-6{padding-left:1.5rem}.pr-10{padding-right:2.5rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-center{text-align:center}.text-right{text-align:right}.align-baseline{vertical-align:baseline}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.italic{font-style:italic}.text-accent{--tw-text-opacity:1;color:var(--fallback-a,oklch(var(--a)/var(--tw-text-opacity,1)))}.text-accent-content{--tw-text-opacity:1;color:var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity,1)))}.text-base-content{--tw-text-opacity:1;color:var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity,1)))}.text-base-content\/40{color:var(--fallback-bc,oklch(var(--bc)/.4))}.text-base-content\/50{color:var(--fallback-bc,oklch(var(--bc)/.5))}.text-base-content\/60{color:var(--fallback-bc,oklch(var(--bc)/.6))}.text-base-content\/70{color:var(--fallback-bc,oklch(var(--bc)/.7))}.text-base-content\/80{color:var(--fallback-bc,oklch(var(--bc)/.8))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-error{--tw-text-opacity:1;color:var(--fallback-er,oklch(var(--er)/var(--tw-text-opacity,1)))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-info{--tw-text-opacity:1;color:var(--fallback-in,oklch(var(--in)/var(--tw-text-opacity,1)))}.text-info-content{--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity,1)))}.text-neutral{--tw-text-opacity:1;color:var(--fallback-n,oklch(var(--n)/var(--tw-text-opacity,1)))}.text-neutral-content{--tw-text-opacity:1;color:var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity,1)))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-orange-600{--tw-text-opacity:1;color:rgb(234 88 12/var(--tw-text-opacity,1))}.text-pink-500{--tw-text-opacity:1;color:rgb(236 72 153/var(--tw-text-opacity,1))}.text-primary{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity,1)))}.text-primary-content{--tw-text-opacity:1;color:var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity,1)))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-secondary{--tw-text-opacity:1;color:var(--fallback-s,oklch(var(--s)/var(--tw-text-opacity,1)))}.text-secondary-content{--tw-text-opacity:1;color:var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity,1)))}.text-sky-400{--tw-text-opacity:1;color:rgb(56 189 248/var(--tw-text-opacity,1))}.text-success{--tw-text-opacity:1;color:var(--fallback-su,oklch(var(--su)/var(--tw-text-opacity,1)))}.text-success-content{--tw-text-opacity:1;color:var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity,1)))}.text-warning{--tw-text-opacity:1;color:var(--fallback-wa,oklch(var(--wa)/var(--tw-text-opacity,1)))}.text-warning-content{--tw-text-opacity:1;color:var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity,1)))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.decoration-dotted{text-decoration-style:dotted}.placeholder-base-content\/70::-moz-placeholder{color:var(--fallback-bc,oklch(var(--bc)/.7))}.placeholder-base-content\/70::placeholder{color:var(--fallback-bc,oklch(var(--bc)/.7))}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-inner{--tw-shadow:inset 0 2px 4px 0 rgba(0,0,0,.05);--tw-shadow-colored:inset 0 2px 4px 0 var(--tw-shadow-color)}.shadow-inner,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-xl{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-2{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-primary{--tw-ring-opacity:1;--tw-ring-color:var(--fallback-p,oklch(var(--p)/var(--tw-ring-opacity,1)))}.ring-offset-2{--tw-ring-offset-width:2px}.blur{--tw-blur:blur(8px)}.blur,.grayscale{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.grayscale{--tw-grayscale:grayscale(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-shadow{transition-duration:.15s;transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{transition-duration:.15s;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}@tailwind daisyui;.leaflet-right-panel{background:#fff;border-radius:4px;box-shadow:0 1px 4px rgba(0,0,0,.3);margin-right:10px;margin-top:80px;transform:none;transition:right .3s ease-in-out;z-index:400}.add-visit-marker{align-items:center;animation:pulse-visit 2s infinite;background:#fff;border:2px solid #007bff;border-radius:50%;box-shadow:0 2px 8px rgba(0,123,255,.3);display:flex;font-size:20px;justify-content:center}@keyframes pulse-visit{0%{box-shadow:0 2px 8px rgba(0,123,255,.3);transform:scale(1)}50%{box-shadow:0 4px 12px rgba(0,123,255,.5);transform:scale(1.1)}to{box-shadow:0 2px 8px rgba(0,123,255,.3);transform:scale(1)}}@keyframes supporter-rainbow-glow{0%{filter:hue-rotate(0deg) drop-shadow(0 0 2px rgba(236,72,153,.4))}25%{filter:hue-rotate(90deg) drop-shadow(0 0 8px rgba(236,72,153,.8))}50%{filter:hue-rotate(180deg) drop-shadow(0 0 2px rgba(236,72,153,.4))}75%{filter:hue-rotate(270deg) drop-shadow(0 0 8px rgba(236,72,153,.8))}to{filter:hue-rotate(1turn) drop-shadow(0 0 2px rgba(236,72,153,.4))}}.visit-form-popup .leaflet-popup-content-wrapper{border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,.15)}.leaflet-right-panel.controls-shifted{right:310px}.leaflet-drawer{background:hsla(0,0%,100%,.5);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15);cursor:default;height:auto;max-height:calc(100% - 20px);opacity:0;position:absolute;right:70px;top:10px;transform:scale(.95);transition:opacity .2s ease-in-out,transform .2s ease-in-out,visibility .2s;visibility:hidden;width:24rem;z-index:450}.leaflet-drawer *{cursor:default}.leaflet-drawer .btn,.leaflet-drawer a,.leaflet-drawer button,.leaflet-drawer input[type=checkbox]{cursor:pointer}.leaflet-drawer.open{opacity:1;transform:scale(1);visibility:visible}.leaflet-control-button,.leaflet-control-layers,.toggle-panel-button{z-index:500}.leaflet-control-custom{align-items:center;background-color:#fff;border-radius:4px;box-shadow:0 1px 4px rgba(0,0,0,.3);cursor:pointer;display:flex;height:30px;justify-content:center;width:30px}.leaflet-control-custom:hover{background-color:#f3f4f6}#selection-tool-button.active{background-color:#60a5fa;color:#fff}#cancel-selection-button{width:100%}em-emoji-picker{--color-border-over:rgba(0,0,0,.1);--color-border:rgba(0,0,0,.05);--font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--rgb-accent:96,165,250;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,.15);max-width:400px;min-width:318px;overflow:auto;position:absolute;resize:horizontal;z-index:1000}[data-theme=dark] em-emoji-picker,html.dark em-emoji-picker{--color-border-over:hsla(0,0%,100%,.1);--color-border:hsla(0,0%,100%,.05);--rgb-accent:96,165,250}@media (max-width:768px){em-emoji-picker{max-width:90vw;min-width:280px}}.color-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;padding:0}.color-input::-webkit-color-swatch-wrapper{padding:0}.color-input::-webkit-color-swatch{border:none;border-radius:.5rem}.color-input::-moz-color-swatch{border:none;border-radius:.5rem}@media (hover:hover){.hover\:btn-ghost:hover:hover{border-color:transparent}@supports (color:oklch(0 0 0)){.hover\:btn-ghost:hover:hover{background-color:var(--fallback-bc,oklch(var(--bc)/.2))}}.hover\:btn-info:hover.btn-outline:hover{--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)))}@supports (color:color-mix(in oklab,black,black)){.hover\:btn-info:hover.btn-outline:hover{background-color:color-mix(in oklab,var(--fallback-in,oklch(var(--in)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-in,oklch(var(--in)/1)) 90%,#000)}}}@supports not (color:oklch(0 0 0)){.hover\:btn-info:hover{--btn-color:var(--fallback-in)}}@supports (color:color-mix(in oklab,black,black)){.hover\:btn-info:hover.btn-outline.btn-active{background-color:color-mix(in oklab,var(--fallback-in,oklch(var(--in)/1)) 90%,#000);border-color:color-mix(in oklab,var(--fallback-in,oklch(var(--in)/1)) 90%,#000)}}@supports (color:oklch(0 0 0)){.hover\:btn-info:hover{--btn-color:var(--in)}}.hover\:btn-info:hover{--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)));outline-color:var(--fallback-in,oklch(var(--in)/1))}.hover\:btn-ghost:hover{background-color:transparent;border-color:transparent;border-width:1px;color:currentColor;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);outline-color:currentColor}.hover\:btn-ghost:hover.btn-active{background-color:var(--fallback-bc,oklch(var(--bc)/.2));border-color:transparent}.hover\:btn-info:hover.btn-outline{--tw-text-opacity:1;color:var(--fallback-in,oklch(var(--in)/var(--tw-text-opacity)))}.hover\:btn-info:hover.btn-outline.btn-active{--tw-text-opacity:1;color:var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)))}.hover\:input-primary:hover{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)))}.hover\:input-primary:hover:focus,.hover\:input-primary:hover:focus-within{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));outline-color:var(--fallback-p,oklch(var(--p)/1))}@media not all and (min-width:768px){.max-md\:timeline-compact,.max-md\:timeline-compact -.timeline-horizontal{--timeline-row-start:0}.max-md\:timeline-compact .timeline-horizontal .timeline-start,.max-md\:timeline-compact .timeline-start{align-self:flex-start;grid-column-end:4;grid-column-start:1;grid-row-end:4;grid-row-start:3;justify-self:center;margin:.25rem}.max-md\:timeline-compact .timeline-horizontal li:has(.timeline-start) .timeline-end,.max-md\:timeline-compact li:has(.timeline-start) .timeline-end{grid-column-start:none;grid-row-start:auto}.max-md\:timeline-compact.timeline-vertical>li{--timeline-col-start:0}.max-md\:timeline-compact.timeline-vertical .timeline-start{align-self:center;grid-column-end:4;grid-column-start:3;grid-row-end:4;grid-row-start:1;justify-self:start}.max-md\:timeline-compact.timeline-vertical li:has(.timeline-start) .timeline-end{grid-column-start:auto;grid-row-start:none}}@media (min-width:1024px){.lg\:stats-horizontal{grid-auto-flow:column}.lg\:stats-horizontal>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;--tw-divide-y-reverse:0;border-width:calc(0px*(1 - var(--tw-divide-y-reverse))) calc(1px*var(--tw-divide-x-reverse)) calc(0px*var(--tw-divide-y-reverse)) calc(1px*(1 - var(--tw-divide-x-reverse)))}.lg\:stats-horizontal{overflow-x:auto}:is([dir=rtl] .lg\:stats-horizontal){--tw-divide-x-reverse:1}}.last\:border-0:last-child{border-width:0}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:scale-\[1\.02\]:hover{--tw-scale-x:1.02;--tw-scale-y:1.02;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:cursor-pointer:hover{cursor:pointer}.hover\:border-primary:hover{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity,1)))}.hover\:border-primary\/40:hover{border-color:var(--fallback-p,oklch(var(--p)/.4))}.hover\:bg-accent:hover{--tw-bg-opacity:1;background-color:var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity,1)))}.hover\:bg-base-200:hover{--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity,1)))}.hover\:bg-base-200\/50:hover{background-color:var(--fallback-b2,oklch(var(--b2)/.5))}.hover\:bg-base-300:hover{--tw-bg-opacity:1;background-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity,1)))}.hover\:bg-blue-50:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.hover\:text-accent-content:hover{--tw-text-opacity:1;color:var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity,1)))}.hover\:text-blue-800:hover{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity,1))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.hover\:text-primary:hover{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity,1)))}.hover\:underline:hover{text-decoration-line:underline}.hover\:no-underline:hover{text-decoration-line:none}.hover\:opacity-80:hover{opacity:.8}.hover\:shadow-2xl:hover{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.hover\:shadow-2xl:hover,.hover\:shadow-lg:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-primary\/20:hover{--tw-shadow-color:var(--fallback-p,oklch(var(--p)/0.2));--tw-shadow:var(--tw-shadow-colored)}.focus\:border-primary:focus{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity,1)))}.focus\:border-transparent:focus{border-color:transparent}.focus\:bg-base-100:focus{--tw-bg-opacity:1;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity,1)))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.group:hover .group-hover\:text-primary{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity,1)))}.group:hover .group-hover\:opacity-100{opacity:1}.peer:checked~.peer-checked\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}}@media (min-width:768px){.md\:h-64{height:16rem}.md\:min-h-64{min-height:16rem}.md\:w-1\/12{width:8.333333%}.md\:w-2\/12{width:16.666667%}.md\:w-2\/3{width:66.666667%}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.md\:text-end{text-align:end}}@media (min-width:1024px){.lg\:col-span-2{grid-column:span 2/span 2}.lg\:mt-0{margin-top:0}.lg\:\!block{display:block!important}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:w-1\/12{width:8.333333%}.lg\:w-1\/2{width:50%}.lg\:w-1\/4{width:25%}.lg\:w-2\/12{width:16.666667%}.lg\:w-3\/4{width:75%}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:flex-row-reverse{flex-direction:row-reverse}.lg\:items-end{align-items:flex-end}.lg\:gap-6{gap:1.5rem}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(0px*var(--tw-space-y-reverse));margin-top:calc(0px*(1 - var(--tw-space-y-reverse)))}.lg\:text-left{text-align:left}} \ No newline at end of file +.timeline-horizontal{--timeline-row-start:0}.max-md\:timeline-compact .timeline-horizontal .timeline-start,.max-md\:timeline-compact .timeline-start{align-self:flex-start;grid-column-end:4;grid-column-start:1;grid-row-end:4;grid-row-start:3;justify-self:center;margin:.25rem}.max-md\:timeline-compact .timeline-horizontal li:has(.timeline-start) .timeline-end,.max-md\:timeline-compact li:has(.timeline-start) .timeline-end{grid-column-start:none;grid-row-start:auto}.max-md\:timeline-compact.timeline-vertical>li{--timeline-col-start:0}.max-md\:timeline-compact.timeline-vertical .timeline-start{align-self:center;grid-column-end:4;grid-column-start:3;grid-row-end:4;grid-row-start:1;justify-self:start}.max-md\:timeline-compact.timeline-vertical li:has(.timeline-start) .timeline-end{grid-column-start:auto;grid-row-start:none}}@media (min-width:1024px){.lg\:stats-horizontal{grid-auto-flow:column}.lg\:stats-horizontal>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;--tw-divide-y-reverse:0;border-width:calc(0px*(1 - var(--tw-divide-y-reverse))) calc(1px*var(--tw-divide-x-reverse)) calc(0px*var(--tw-divide-y-reverse)) calc(1px*(1 - var(--tw-divide-x-reverse)))}.lg\:stats-horizontal{overflow-x:auto}:is([dir=rtl] .lg\:stats-horizontal){--tw-divide-x-reverse:1}}.last\:border-0:last-child{border-width:0}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:scale-\[1\.02\]:hover{--tw-scale-x:1.02;--tw-scale-y:1.02;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:cursor-pointer:hover{cursor:pointer}.hover\:border-primary:hover{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity,1)))}.hover\:border-primary\/40:hover{border-color:var(--fallback-p,oklch(var(--p)/.4))}.hover\:bg-accent:hover{--tw-bg-opacity:1;background-color:var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity,1)))}.hover\:bg-base-200:hover{--tw-bg-opacity:1;background-color:var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity,1)))}.hover\:bg-base-200\/50:hover{background-color:var(--fallback-b2,oklch(var(--b2)/.5))}.hover\:bg-base-300:hover{--tw-bg-opacity:1;background-color:var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity,1)))}.hover\:bg-blue-50:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.hover\:text-accent-content:hover{--tw-text-opacity:1;color:var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity,1)))}.hover\:text-blue-800:hover{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity,1))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.hover\:text-primary:hover{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity,1)))}.hover\:underline:hover{text-decoration-line:underline}.hover\:no-underline:hover{text-decoration-line:none}.hover\:opacity-80:hover{opacity:.8}.hover\:shadow-2xl:hover{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.hover\:shadow-2xl:hover,.hover\:shadow-lg:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-lg:hover{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-primary\/20:hover{--tw-shadow-color:var(--fallback-p,oklch(var(--p)/0.2));--tw-shadow:var(--tw-shadow-colored)}.focus\:border-primary:focus{--tw-border-opacity:1;border-color:var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity,1)))}.focus\:border-transparent:focus{border-color:transparent}.focus\:bg-base-100:focus{--tw-bg-opacity:1;background-color:var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity,1)))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.group:hover .group-hover\:text-primary{--tw-text-opacity:1;color:var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity,1)))}.group:hover .group-hover\:opacity-100{opacity:1}.peer:checked~.peer-checked\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}}@media (min-width:768px){.md\:h-64{height:16rem}.md\:min-h-64{min-height:16rem}.md\:w-1\/12{width:8.333333%}.md\:w-2\/12{width:16.666667%}.md\:w-2\/3{width:66.666667%}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.md\:text-end{text-align:end}}@media (min-width:1024px){.lg\:col-span-2{grid-column:span 2/span 2}.lg\:mt-0{margin-top:0}.lg\:\!block{display:block!important}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:w-1\/12{width:8.333333%}.lg\:w-1\/2{width:50%}.lg\:w-1\/4{width:25%}.lg\:w-2\/12{width:16.666667%}.lg\:w-3\/4{width:75%}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:flex-row-reverse{flex-direction:row-reverse}.lg\:items-end{align-items:flex-end}.lg\:gap-6{gap:1.5rem}.lg\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.lg\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(0px*var(--tw-space-y-reverse));margin-top:calc(0px*(1 - var(--tw-space-y-reverse)))}.lg\:text-left{text-align:left}} diff --git a/app/assets/svg/icons/flags/landscape/ad.svg b/app/assets/svg/icons/flags/landscape/ad.svg new file mode 100644 index 000000000..199ff198e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ad.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ae.svg b/app/assets/svg/icons/flags/landscape/ae.svg new file mode 100644 index 000000000..651ac8523 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ae.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/af.svg b/app/assets/svg/icons/flags/landscape/af.svg new file mode 100644 index 000000000..4dbe4556e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/af.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ag.svg b/app/assets/svg/icons/flags/landscape/ag.svg new file mode 100644 index 000000000..243c3d8f9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ag.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ai.svg b/app/assets/svg/icons/flags/landscape/ai.svg new file mode 100644 index 000000000..9c2ea3398 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ai.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/al.svg b/app/assets/svg/icons/flags/landscape/al.svg new file mode 100644 index 000000000..e85d95f0f --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/al.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/am.svg b/app/assets/svg/icons/flags/landscape/am.svg new file mode 100644 index 000000000..99fa4dc59 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/am.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ao.svg b/app/assets/svg/icons/flags/landscape/ao.svg new file mode 100644 index 000000000..b73b1ec5e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ao.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/aq.svg b/app/assets/svg/icons/flags/landscape/aq.svg new file mode 100644 index 000000000..c7e353624 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/aq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ar.svg b/app/assets/svg/icons/flags/landscape/ar.svg new file mode 100644 index 000000000..c753da103 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ar.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/arab.svg b/app/assets/svg/icons/flags/landscape/arab.svg new file mode 100644 index 000000000..9ef079f63 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/arab.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/as.svg b/app/assets/svg/icons/flags/landscape/as.svg new file mode 100644 index 000000000..82459dec1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/as.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/asean.svg b/app/assets/svg/icons/flags/landscape/asean.svg new file mode 100644 index 000000000..189ae0205 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/asean.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/at.svg b/app/assets/svg/icons/flags/landscape/at.svg new file mode 100644 index 000000000..9d2775c08 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/at.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/au.svg b/app/assets/svg/icons/flags/landscape/au.svg new file mode 100644 index 000000000..96e80768b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/au.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/aw.svg b/app/assets/svg/icons/flags/landscape/aw.svg new file mode 100644 index 000000000..413b7c45b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/aw.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ax.svg b/app/assets/svg/icons/flags/landscape/ax.svg new file mode 100644 index 000000000..0584d713b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ax.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/az.svg b/app/assets/svg/icons/flags/landscape/az.svg new file mode 100644 index 000000000..355752211 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/az.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ba.svg b/app/assets/svg/icons/flags/landscape/ba.svg new file mode 100644 index 000000000..93bd9cf93 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ba.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bb.svg b/app/assets/svg/icons/flags/landscape/bb.svg new file mode 100644 index 000000000..cecd5cc33 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bb.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bd.svg b/app/assets/svg/icons/flags/landscape/bd.svg new file mode 100644 index 000000000..16b794deb --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bd.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/be.svg b/app/assets/svg/icons/flags/landscape/be.svg new file mode 100644 index 000000000..ac706a0b5 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/be.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bf.svg b/app/assets/svg/icons/flags/landscape/bf.svg new file mode 100644 index 000000000..471382258 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bf.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bg.svg b/app/assets/svg/icons/flags/landscape/bg.svg new file mode 100644 index 000000000..af2d0d07c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bh.svg b/app/assets/svg/icons/flags/landscape/bh.svg new file mode 100644 index 000000000..7a2ea549b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bh.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/bi.svg b/app/assets/svg/icons/flags/landscape/bi.svg new file mode 100644 index 000000000..a4434a955 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bi.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bj.svg b/app/assets/svg/icons/flags/landscape/bj.svg new file mode 100644 index 000000000..0846724d1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bj.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bl.svg b/app/assets/svg/icons/flags/landscape/bl.svg new file mode 100644 index 000000000..f84cbbaeb --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bl.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bm.svg b/app/assets/svg/icons/flags/landscape/bm.svg new file mode 100644 index 000000000..f43a5ebc8 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bm.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bn.svg b/app/assets/svg/icons/flags/landscape/bn.svg new file mode 100644 index 000000000..f544c25e2 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bn.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bo.svg b/app/assets/svg/icons/flags/landscape/bo.svg new file mode 100644 index 000000000..7658e3f6c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bo.svg @@ -0,0 +1,673 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bq.svg b/app/assets/svg/icons/flags/landscape/bq.svg new file mode 100644 index 000000000..0e6bc76e6 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/br.svg b/app/assets/svg/icons/flags/landscape/br.svg new file mode 100644 index 000000000..719a763ca --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/br.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bs.svg b/app/assets/svg/icons/flags/landscape/bs.svg new file mode 100644 index 000000000..5cc918e5a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bs.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bt.svg b/app/assets/svg/icons/flags/landscape/bt.svg new file mode 100644 index 000000000..20aef3a63 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bt.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bv.svg b/app/assets/svg/icons/flags/landscape/bv.svg new file mode 100644 index 000000000..40e16d948 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bv.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bw.svg b/app/assets/svg/icons/flags/landscape/bw.svg new file mode 100644 index 000000000..3435608d6 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bw.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/by.svg b/app/assets/svg/icons/flags/landscape/by.svg new file mode 100644 index 000000000..948784ff1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/by.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/bz.svg b/app/assets/svg/icons/flags/landscape/bz.svg new file mode 100644 index 000000000..d81b16c23 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/bz.svg @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ca.svg b/app/assets/svg/icons/flags/landscape/ca.svg new file mode 100644 index 000000000..c9b23b498 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ca.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/cc.svg b/app/assets/svg/icons/flags/landscape/cc.svg new file mode 100644 index 000000000..a42dec667 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cc.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cd.svg b/app/assets/svg/icons/flags/landscape/cd.svg new file mode 100644 index 000000000..b9cf52894 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cd.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cefta.svg b/app/assets/svg/icons/flags/landscape/cefta.svg new file mode 100644 index 000000000..f748d08a1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cefta.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cf.svg b/app/assets/svg/icons/flags/landscape/cf.svg new file mode 100644 index 000000000..a6cd3670f --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cf.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cg.svg b/app/assets/svg/icons/flags/landscape/cg.svg new file mode 100644 index 000000000..f5a0e42d4 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cg.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ch.svg b/app/assets/svg/icons/flags/landscape/ch.svg new file mode 100644 index 000000000..b42d6709c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ch.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ci.svg b/app/assets/svg/icons/flags/landscape/ci.svg new file mode 100644 index 000000000..e400f0c1c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ci.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ck.svg b/app/assets/svg/icons/flags/landscape/ck.svg new file mode 100644 index 000000000..18e547b17 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ck.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cl.svg b/app/assets/svg/icons/flags/landscape/cl.svg new file mode 100644 index 000000000..5b3c72fa7 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cl.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cm.svg b/app/assets/svg/icons/flags/landscape/cm.svg new file mode 100644 index 000000000..70adc8b68 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cm.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cn.svg b/app/assets/svg/icons/flags/landscape/cn.svg new file mode 100644 index 000000000..10d3489a0 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cn.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/co.svg b/app/assets/svg/icons/flags/landscape/co.svg new file mode 100644 index 000000000..ebd0a0fb2 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/co.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cp.svg b/app/assets/svg/icons/flags/landscape/cp.svg new file mode 100644 index 000000000..b8aa9cfd6 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cp.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cr.svg b/app/assets/svg/icons/flags/landscape/cr.svg new file mode 100644 index 000000000..5a409eebb --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cr.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cu.svg b/app/assets/svg/icons/flags/landscape/cu.svg new file mode 100644 index 000000000..053c9ee3a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cu.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cv.svg b/app/assets/svg/icons/flags/landscape/cv.svg new file mode 100644 index 000000000..aec899490 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cv.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cw.svg b/app/assets/svg/icons/flags/landscape/cw.svg new file mode 100644 index 000000000..bb0ece22e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cw.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cx.svg b/app/assets/svg/icons/flags/landscape/cx.svg new file mode 100644 index 000000000..3a83c23f6 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cx.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cy.svg b/app/assets/svg/icons/flags/landscape/cy.svg new file mode 100644 index 000000000..ee4b0c78c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cy.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/cz.svg b/app/assets/svg/icons/flags/landscape/cz.svg new file mode 100644 index 000000000..7913de389 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/cz.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/de.svg b/app/assets/svg/icons/flags/landscape/de.svg new file mode 100644 index 000000000..71aa2d2c3 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/de.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/dg.svg b/app/assets/svg/icons/flags/landscape/dg.svg new file mode 100644 index 000000000..dfee2bb93 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/dg.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/dj.svg b/app/assets/svg/icons/flags/landscape/dj.svg new file mode 100644 index 000000000..9b00a8205 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/dj.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/dk.svg b/app/assets/svg/icons/flags/landscape/dk.svg new file mode 100644 index 000000000..563277f81 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/dk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/dm.svg b/app/assets/svg/icons/flags/landscape/dm.svg new file mode 100644 index 000000000..5aa9cea5f --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/dm.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/do.svg b/app/assets/svg/icons/flags/landscape/do.svg new file mode 100644 index 000000000..6de2b268d --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/do.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/dz.svg b/app/assets/svg/icons/flags/landscape/dz.svg new file mode 100644 index 000000000..5ff29a74a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/dz.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/eac.svg b/app/assets/svg/icons/flags/landscape/eac.svg new file mode 100644 index 000000000..59d02d218 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/eac.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ec.svg b/app/assets/svg/icons/flags/landscape/ec.svg new file mode 100644 index 000000000..88c50bf61 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ec.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ee.svg b/app/assets/svg/icons/flags/landscape/ee.svg new file mode 100644 index 000000000..8b98c2c42 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ee.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/eg.svg b/app/assets/svg/icons/flags/landscape/eg.svg new file mode 100644 index 000000000..88e32b3ae --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/eg.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/eh.svg b/app/assets/svg/icons/flags/landscape/eh.svg new file mode 100644 index 000000000..6aec72883 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/eh.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/er.svg b/app/assets/svg/icons/flags/landscape/er.svg new file mode 100644 index 000000000..48a13b47f --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/er.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/es-ct.svg b/app/assets/svg/icons/flags/landscape/es-ct.svg new file mode 100644 index 000000000..4d8591140 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/es-ct.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/es-ga.svg b/app/assets/svg/icons/flags/landscape/es-ga.svg new file mode 100644 index 000000000..573ca45da --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/es-ga.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/es-pv.svg b/app/assets/svg/icons/flags/landscape/es-pv.svg new file mode 100644 index 000000000..63c19f417 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/es-pv.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/es.svg b/app/assets/svg/icons/flags/landscape/es.svg new file mode 100644 index 000000000..a296ebf7e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/es.svg @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/et.svg b/app/assets/svg/icons/flags/landscape/et.svg new file mode 100644 index 000000000..3f99be486 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/et.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/eu.svg b/app/assets/svg/icons/flags/landscape/eu.svg new file mode 100644 index 000000000..b0874c1ed --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/eu.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/fi.svg b/app/assets/svg/icons/flags/landscape/fi.svg new file mode 100644 index 000000000..470be2d07 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/fi.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/fj.svg b/app/assets/svg/icons/flags/landscape/fj.svg new file mode 100644 index 000000000..332ae61d0 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/fj.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/fk.svg b/app/assets/svg/icons/flags/landscape/fk.svg new file mode 100644 index 000000000..a0dace837 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/fk.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/fm.svg b/app/assets/svg/icons/flags/landscape/fm.svg new file mode 100644 index 000000000..c1b7c9778 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/fm.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/fo.svg b/app/assets/svg/icons/flags/landscape/fo.svg new file mode 100644 index 000000000..f802d285a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/fo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/fr.svg b/app/assets/svg/icons/flags/landscape/fr.svg new file mode 100644 index 000000000..4110e59e4 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/fr.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ga.svg b/app/assets/svg/icons/flags/landscape/ga.svg new file mode 100644 index 000000000..76edab429 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ga.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gb-eng.svg b/app/assets/svg/icons/flags/landscape/gb-eng.svg new file mode 100644 index 000000000..12e3b67d5 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gb-eng.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gb-nir.svg b/app/assets/svg/icons/flags/landscape/gb-nir.svg new file mode 100644 index 000000000..e22190aae --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gb-nir.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gb-sct.svg b/app/assets/svg/icons/flags/landscape/gb-sct.svg new file mode 100644 index 000000000..f50cd322a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gb-sct.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/gb-wls.svg b/app/assets/svg/icons/flags/landscape/gb-wls.svg new file mode 100644 index 000000000..d7f57912d --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gb-wls.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gb.svg b/app/assets/svg/icons/flags/landscape/gb.svg new file mode 100644 index 000000000..799138319 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gb.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gd.svg b/app/assets/svg/icons/flags/landscape/gd.svg new file mode 100644 index 000000000..b3d250db9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gd.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ge.svg b/app/assets/svg/icons/flags/landscape/ge.svg new file mode 100644 index 000000000..ab08a9ab4 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ge.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gf.svg b/app/assets/svg/icons/flags/landscape/gf.svg new file mode 100644 index 000000000..f8fe94c65 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gf.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gg.svg b/app/assets/svg/icons/flags/landscape/gg.svg new file mode 100644 index 000000000..f8216c8bc --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gh.svg b/app/assets/svg/icons/flags/landscape/gh.svg new file mode 100644 index 000000000..5c3e3e69a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gh.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gi.svg b/app/assets/svg/icons/flags/landscape/gi.svg new file mode 100644 index 000000000..a5d7570dd --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gi.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gl.svg b/app/assets/svg/icons/flags/landscape/gl.svg new file mode 100644 index 000000000..eb5a52e9e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gl.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/gm.svg b/app/assets/svg/icons/flags/landscape/gm.svg new file mode 100644 index 000000000..8fe9d6692 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gm.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gn.svg b/app/assets/svg/icons/flags/landscape/gn.svg new file mode 100644 index 000000000..40d6ad4f0 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gn.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gp.svg b/app/assets/svg/icons/flags/landscape/gp.svg new file mode 100644 index 000000000..ee55c4bcd --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gp.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gq.svg b/app/assets/svg/icons/flags/landscape/gq.svg new file mode 100644 index 000000000..64c8eb220 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gq.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gr.svg b/app/assets/svg/icons/flags/landscape/gr.svg new file mode 100644 index 000000000..599741eec --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gr.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gs.svg b/app/assets/svg/icons/flags/landscape/gs.svg new file mode 100644 index 000000000..29db9b942 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gs.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gt.svg b/app/assets/svg/icons/flags/landscape/gt.svg new file mode 100644 index 000000000..7df9df579 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gt.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gu.svg b/app/assets/svg/icons/flags/landscape/gu.svg new file mode 100644 index 000000000..3b95219a0 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gu.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gw.svg b/app/assets/svg/icons/flags/landscape/gw.svg new file mode 100644 index 000000000..d470bac9f --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gw.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/gy.svg b/app/assets/svg/icons/flags/landscape/gy.svg new file mode 100644 index 000000000..569fb5627 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/gy.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/hk.svg b/app/assets/svg/icons/flags/landscape/hk.svg new file mode 100644 index 000000000..4fd55bc14 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/hk.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/hm.svg b/app/assets/svg/icons/flags/landscape/hm.svg new file mode 100644 index 000000000..815c48208 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/hm.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/hn.svg b/app/assets/svg/icons/flags/landscape/hn.svg new file mode 100644 index 000000000..11fde67db --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/hn.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/hr.svg b/app/assets/svg/icons/flags/landscape/hr.svg new file mode 100644 index 000000000..dde825c30 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/hr.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ht.svg b/app/assets/svg/icons/flags/landscape/ht.svg new file mode 100644 index 000000000..8e8efc46b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ht.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/hu.svg b/app/assets/svg/icons/flags/landscape/hu.svg new file mode 100644 index 000000000..baddf7f5e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/hu.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ic.svg b/app/assets/svg/icons/flags/landscape/ic.svg new file mode 100644 index 000000000..81e6ee2e1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ic.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/id.svg b/app/assets/svg/icons/flags/landscape/id.svg new file mode 100644 index 000000000..3b7c8fcfd --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/id.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/ie.svg b/app/assets/svg/icons/flags/landscape/ie.svg new file mode 100644 index 000000000..049be14de --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ie.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/il.svg b/app/assets/svg/icons/flags/landscape/il.svg new file mode 100644 index 000000000..f43be7e8e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/il.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/im.svg b/app/assets/svg/icons/flags/landscape/im.svg new file mode 100644 index 000000000..fe6a59a1a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/im.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/in.svg b/app/assets/svg/icons/flags/landscape/in.svg new file mode 100644 index 000000000..bc47d7491 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/in.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/io.svg b/app/assets/svg/icons/flags/landscape/io.svg new file mode 100644 index 000000000..3058f7dff --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/io.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/iq.svg b/app/assets/svg/icons/flags/landscape/iq.svg new file mode 100644 index 000000000..804451474 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/iq.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ir.svg b/app/assets/svg/icons/flags/landscape/ir.svg new file mode 100644 index 000000000..8c6d51621 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ir.svg @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/is.svg b/app/assets/svg/icons/flags/landscape/is.svg new file mode 100644 index 000000000..a6588afae --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/is.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/it.svg b/app/assets/svg/icons/flags/landscape/it.svg new file mode 100644 index 000000000..20a8bfdcc --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/it.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/je.svg b/app/assets/svg/icons/flags/landscape/je.svg new file mode 100644 index 000000000..70a8754ef --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/je.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/jm.svg b/app/assets/svg/icons/flags/landscape/jm.svg new file mode 100644 index 000000000..269df0383 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/jm.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/jo.svg b/app/assets/svg/icons/flags/landscape/jo.svg new file mode 100644 index 000000000..d6f927d44 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/jo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/jp.svg b/app/assets/svg/icons/flags/landscape/jp.svg new file mode 100644 index 000000000..cc1c181ce --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/jp.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ke.svg b/app/assets/svg/icons/flags/landscape/ke.svg new file mode 100644 index 000000000..3a67ca3cc --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ke.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/kg.svg b/app/assets/svg/icons/flags/landscape/kg.svg new file mode 100644 index 000000000..e26db9535 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/kg.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/kh.svg b/app/assets/svg/icons/flags/landscape/kh.svg new file mode 100644 index 000000000..a7d52f2cb --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/kh.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ki.svg b/app/assets/svg/icons/flags/landscape/ki.svg new file mode 100644 index 000000000..fda03f37b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ki.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/km.svg b/app/assets/svg/icons/flags/landscape/km.svg new file mode 100644 index 000000000..414d65e47 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/km.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/kn.svg b/app/assets/svg/icons/flags/landscape/kn.svg new file mode 100644 index 000000000..47fe64d61 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/kn.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/kp.svg b/app/assets/svg/icons/flags/landscape/kp.svg new file mode 100644 index 000000000..ad1b713f1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/kp.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/kr.svg b/app/assets/svg/icons/flags/landscape/kr.svg new file mode 100644 index 000000000..6947eab2b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/kr.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/kw.svg b/app/assets/svg/icons/flags/landscape/kw.svg new file mode 100644 index 000000000..3dd89e996 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/kw.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ky.svg b/app/assets/svg/icons/flags/landscape/ky.svg new file mode 100644 index 000000000..aeaa7e08c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ky.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/kz.svg b/app/assets/svg/icons/flags/landscape/kz.svg new file mode 100644 index 000000000..2fac45bda --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/kz.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/la.svg b/app/assets/svg/icons/flags/landscape/la.svg new file mode 100644 index 000000000..6aea6b72b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/la.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/lb.svg b/app/assets/svg/icons/flags/landscape/lb.svg new file mode 100644 index 000000000..bde2581d2 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/lb.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/lc.svg b/app/assets/svg/icons/flags/landscape/lc.svg new file mode 100644 index 000000000..bb256541c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/lc.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/li.svg b/app/assets/svg/icons/flags/landscape/li.svg new file mode 100644 index 000000000..7a4d18324 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/li.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/lk.svg b/app/assets/svg/icons/flags/landscape/lk.svg new file mode 100644 index 000000000..cbd660a54 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/lk.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/lr.svg b/app/assets/svg/icons/flags/landscape/lr.svg new file mode 100644 index 000000000..e482ab9d7 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/lr.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ls.svg b/app/assets/svg/icons/flags/landscape/ls.svg new file mode 100644 index 000000000..a7c01a98f --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ls.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/lt.svg b/app/assets/svg/icons/flags/landscape/lt.svg new file mode 100644 index 000000000..90ec5d240 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/lt.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/lu.svg b/app/assets/svg/icons/flags/landscape/lu.svg new file mode 100644 index 000000000..cc1220681 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/lu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/lv.svg b/app/assets/svg/icons/flags/landscape/lv.svg new file mode 100644 index 000000000..6a9e75ec9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/lv.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ly.svg b/app/assets/svg/icons/flags/landscape/ly.svg new file mode 100644 index 000000000..1eaa51e46 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ly.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ma.svg b/app/assets/svg/icons/flags/landscape/ma.svg new file mode 100644 index 000000000..7ce56eff7 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ma.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/mc.svg b/app/assets/svg/icons/flags/landscape/mc.svg new file mode 100644 index 000000000..9cb6c9e8a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mc.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/md.svg b/app/assets/svg/icons/flags/landscape/md.svg new file mode 100644 index 000000000..e9ba506a2 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/md.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/me.svg b/app/assets/svg/icons/flags/landscape/me.svg new file mode 100644 index 000000000..297888c7b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/me.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mf.svg b/app/assets/svg/icons/flags/landscape/mf.svg new file mode 100644 index 000000000..6305edc1c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mf.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mg.svg b/app/assets/svg/icons/flags/landscape/mg.svg new file mode 100644 index 000000000..5fa2d2440 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mg.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mh.svg b/app/assets/svg/icons/flags/landscape/mh.svg new file mode 100644 index 000000000..7b9f49075 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mh.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mk.svg b/app/assets/svg/icons/flags/landscape/mk.svg new file mode 100644 index 000000000..4f5cae77e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ml.svg b/app/assets/svg/icons/flags/landscape/ml.svg new file mode 100644 index 000000000..6f6b71695 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ml.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mm.svg b/app/assets/svg/icons/flags/landscape/mm.svg new file mode 100644 index 000000000..42b4dee2b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mm.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mn.svg b/app/assets/svg/icons/flags/landscape/mn.svg new file mode 100644 index 000000000..6a38a71fc --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mn.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mo.svg b/app/assets/svg/icons/flags/landscape/mo.svg new file mode 100644 index 000000000..f638b6cbc --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mp.svg b/app/assets/svg/icons/flags/landscape/mp.svg new file mode 100644 index 000000000..26bfa2217 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mp.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mq.svg b/app/assets/svg/icons/flags/landscape/mq.svg new file mode 100644 index 000000000..b221951e3 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mr.svg b/app/assets/svg/icons/flags/landscape/mr.svg new file mode 100644 index 000000000..d859972c5 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mr.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ms.svg b/app/assets/svg/icons/flags/landscape/ms.svg new file mode 100644 index 000000000..4367505bc --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ms.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mt.svg b/app/assets/svg/icons/flags/landscape/mt.svg new file mode 100644 index 000000000..5d5d7c80a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mt.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mu.svg b/app/assets/svg/icons/flags/landscape/mu.svg new file mode 100644 index 000000000..82d7a3bec --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mu.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mv.svg b/app/assets/svg/icons/flags/landscape/mv.svg new file mode 100644 index 000000000..10450f984 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mv.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mw.svg b/app/assets/svg/icons/flags/landscape/mw.svg new file mode 100644 index 000000000..137ff8789 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mw.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mx.svg b/app/assets/svg/icons/flags/landscape/mx.svg new file mode 100644 index 000000000..e3ec2bc59 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mx.svg @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/my.svg b/app/assets/svg/icons/flags/landscape/my.svg new file mode 100644 index 000000000..115f864d8 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/my.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/mz.svg b/app/assets/svg/icons/flags/landscape/mz.svg new file mode 100644 index 000000000..0f94c3a1a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/mz.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/na.svg b/app/assets/svg/icons/flags/landscape/na.svg new file mode 100644 index 000000000..35b9f783e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/na.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/nc.svg b/app/assets/svg/icons/flags/landscape/nc.svg new file mode 100644 index 000000000..fa1555169 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/nc.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ne.svg b/app/assets/svg/icons/flags/landscape/ne.svg new file mode 100644 index 000000000..39a82b827 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ne.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/nf.svg b/app/assets/svg/icons/flags/landscape/nf.svg new file mode 100644 index 000000000..fd61b25c1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/nf.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ng.svg b/app/assets/svg/icons/flags/landscape/ng.svg new file mode 100644 index 000000000..81eb35f78 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ng.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ni.svg b/app/assets/svg/icons/flags/landscape/ni.svg new file mode 100644 index 000000000..e4861f5ab --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ni.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/nl.svg b/app/assets/svg/icons/flags/landscape/nl.svg new file mode 100644 index 000000000..e90f5b035 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/nl.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/no.svg b/app/assets/svg/icons/flags/landscape/no.svg new file mode 100644 index 000000000..a5f2a152a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/no.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/np.svg b/app/assets/svg/icons/flags/landscape/np.svg new file mode 100644 index 000000000..624285684 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/np.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/nr.svg b/app/assets/svg/icons/flags/landscape/nr.svg new file mode 100644 index 000000000..ff394c411 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/nr.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/nu.svg b/app/assets/svg/icons/flags/landscape/nu.svg new file mode 100644 index 000000000..4067bafff --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/nu.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/nz.svg b/app/assets/svg/icons/flags/landscape/nz.svg new file mode 100644 index 000000000..935d8a749 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/nz.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/om.svg b/app/assets/svg/icons/flags/landscape/om.svg new file mode 100644 index 000000000..4f1461a00 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/om.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pa.svg b/app/assets/svg/icons/flags/landscape/pa.svg new file mode 100644 index 000000000..8dc03bc61 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pa.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pc.svg b/app/assets/svg/icons/flags/landscape/pc.svg new file mode 100644 index 000000000..5202d6d62 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pc.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pe.svg b/app/assets/svg/icons/flags/landscape/pe.svg new file mode 100644 index 000000000..33e6cfd41 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pe.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/pf.svg b/app/assets/svg/icons/flags/landscape/pf.svg new file mode 100644 index 000000000..bea0354d5 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pf.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pg.svg b/app/assets/svg/icons/flags/landscape/pg.svg new file mode 100644 index 000000000..7b7e77aad --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ph.svg b/app/assets/svg/icons/flags/landscape/ph.svg new file mode 100644 index 000000000..b910e24cd --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ph.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pk.svg b/app/assets/svg/icons/flags/landscape/pk.svg new file mode 100644 index 000000000..4ddc19f8e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pk.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pl.svg b/app/assets/svg/icons/flags/landscape/pl.svg new file mode 100644 index 000000000..0fa514524 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pl.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pm.svg b/app/assets/svg/icons/flags/landscape/pm.svg new file mode 100644 index 000000000..19a9330a3 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pm.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pn.svg b/app/assets/svg/icons/flags/landscape/pn.svg new file mode 100644 index 000000000..209ea71a1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pn.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pr.svg b/app/assets/svg/icons/flags/landscape/pr.svg new file mode 100644 index 000000000..ec51831dc --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pr.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ps.svg b/app/assets/svg/icons/flags/landscape/ps.svg new file mode 100644 index 000000000..362d4359b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ps.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pt.svg b/app/assets/svg/icons/flags/landscape/pt.svg new file mode 100644 index 000000000..2767cd4e9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pt.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/pw.svg b/app/assets/svg/icons/flags/landscape/pw.svg new file mode 100644 index 000000000..9f89c5f14 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/pw.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/py.svg b/app/assets/svg/icons/flags/landscape/py.svg new file mode 100644 index 000000000..abccd8799 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/py.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/qa.svg b/app/assets/svg/icons/flags/landscape/qa.svg new file mode 100644 index 000000000..901f3fa76 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/qa.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/re.svg b/app/assets/svg/icons/flags/landscape/re.svg new file mode 100644 index 000000000..64e788e01 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/re.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ro.svg b/app/assets/svg/icons/flags/landscape/ro.svg new file mode 100644 index 000000000..fda0f7bec --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ro.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/rs.svg b/app/assets/svg/icons/flags/landscape/rs.svg new file mode 100644 index 000000000..6d4f74d76 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/rs.svg @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ru.svg b/app/assets/svg/icons/flags/landscape/ru.svg new file mode 100644 index 000000000..cf243011a --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ru.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/rw.svg b/app/assets/svg/icons/flags/landscape/rw.svg new file mode 100644 index 000000000..06e26ae44 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/rw.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sa.svg b/app/assets/svg/icons/flags/landscape/sa.svg new file mode 100644 index 000000000..596cf48bb --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sa.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sb.svg b/app/assets/svg/icons/flags/landscape/sb.svg new file mode 100644 index 000000000..6066f94cd --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sb.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sc.svg b/app/assets/svg/icons/flags/landscape/sc.svg new file mode 100644 index 000000000..9a46b369b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sc.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sd.svg b/app/assets/svg/icons/flags/landscape/sd.svg new file mode 100644 index 000000000..12818b411 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sd.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/se.svg b/app/assets/svg/icons/flags/landscape/se.svg new file mode 100644 index 000000000..8ba745aca --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/se.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/sg.svg b/app/assets/svg/icons/flags/landscape/sg.svg new file mode 100644 index 000000000..c4dd4ac9e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sg.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sh-ac.svg b/app/assets/svg/icons/flags/landscape/sh-ac.svg new file mode 100644 index 000000000..c43b301ef --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sh-ac.svg @@ -0,0 +1,689 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sh-hl.svg b/app/assets/svg/icons/flags/landscape/sh-hl.svg new file mode 100644 index 000000000..2150bf609 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sh-hl.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sh-ta.svg b/app/assets/svg/icons/flags/landscape/sh-ta.svg new file mode 100644 index 000000000..ba390631c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sh-ta.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sh.svg b/app/assets/svg/icons/flags/landscape/sh.svg new file mode 100644 index 000000000..7aba0aec8 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sh.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/si.svg b/app/assets/svg/icons/flags/landscape/si.svg new file mode 100644 index 000000000..1bbdd94fd --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/si.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sj.svg b/app/assets/svg/icons/flags/landscape/sj.svg new file mode 100644 index 000000000..bb2799ce7 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sj.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sk.svg b/app/assets/svg/icons/flags/landscape/sk.svg new file mode 100644 index 000000000..676018e62 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sk.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sl.svg b/app/assets/svg/icons/flags/landscape/sl.svg new file mode 100644 index 000000000..a07baf75b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sl.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sm.svg b/app/assets/svg/icons/flags/landscape/sm.svg new file mode 100644 index 000000000..e41d2f776 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sm.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sn.svg b/app/assets/svg/icons/flags/landscape/sn.svg new file mode 100644 index 000000000..7c0673d6d --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sn.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/so.svg b/app/assets/svg/icons/flags/landscape/so.svg new file mode 100644 index 000000000..a581ac63c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/so.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sr.svg b/app/assets/svg/icons/flags/landscape/sr.svg new file mode 100644 index 000000000..5e71c4002 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sr.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ss.svg b/app/assets/svg/icons/flags/landscape/ss.svg new file mode 100644 index 000000000..b257aa0b3 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ss.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/st.svg b/app/assets/svg/icons/flags/landscape/st.svg new file mode 100644 index 000000000..1294bcb70 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/st.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sv.svg b/app/assets/svg/icons/flags/landscape/sv.svg new file mode 100644 index 000000000..cbc674a6e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sv.svg @@ -0,0 +1,593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sx.svg b/app/assets/svg/icons/flags/landscape/sx.svg new file mode 100644 index 000000000..ac7856178 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sx.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sy.svg b/app/assets/svg/icons/flags/landscape/sy.svg new file mode 100644 index 000000000..97c05cfc9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sy.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/sz.svg b/app/assets/svg/icons/flags/landscape/sz.svg new file mode 100644 index 000000000..eb538e447 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/sz.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tc.svg b/app/assets/svg/icons/flags/landscape/tc.svg new file mode 100644 index 000000000..125897107 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tc.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/td.svg b/app/assets/svg/icons/flags/landscape/td.svg new file mode 100644 index 000000000..fa3bd927c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/td.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tf.svg b/app/assets/svg/icons/flags/landscape/tf.svg new file mode 100644 index 000000000..fba233563 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tf.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tg.svg b/app/assets/svg/icons/flags/landscape/tg.svg new file mode 100644 index 000000000..9d6ea6c5d --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tg.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/th.svg b/app/assets/svg/icons/flags/landscape/th.svg new file mode 100644 index 000000000..1e93a61e9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/th.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tj.svg b/app/assets/svg/icons/flags/landscape/tj.svg new file mode 100644 index 000000000..f8c9a0371 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tj.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tk.svg b/app/assets/svg/icons/flags/landscape/tk.svg new file mode 100644 index 000000000..05d3e86ce --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tl.svg b/app/assets/svg/icons/flags/landscape/tl.svg new file mode 100644 index 000000000..3d0701a2c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tl.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tm.svg b/app/assets/svg/icons/flags/landscape/tm.svg new file mode 100644 index 000000000..4154ed765 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tm.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tn.svg b/app/assets/svg/icons/flags/landscape/tn.svg new file mode 100644 index 000000000..5735c1984 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tn.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/to.svg b/app/assets/svg/icons/flags/landscape/to.svg new file mode 100644 index 000000000..d07233706 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/to.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tr.svg b/app/assets/svg/icons/flags/landscape/tr.svg new file mode 100644 index 000000000..b96da21f0 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tr.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tt.svg b/app/assets/svg/icons/flags/landscape/tt.svg new file mode 100644 index 000000000..bc24938cf --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tt.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tv.svg b/app/assets/svg/icons/flags/landscape/tv.svg new file mode 100644 index 000000000..675210ec5 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tv.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tw.svg b/app/assets/svg/icons/flags/landscape/tw.svg new file mode 100644 index 000000000..57fd98b43 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tw.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/tz.svg b/app/assets/svg/icons/flags/landscape/tz.svg new file mode 100644 index 000000000..a2cfbca42 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/tz.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ua.svg b/app/assets/svg/icons/flags/landscape/ua.svg new file mode 100644 index 000000000..a339eb1b9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ua.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ug.svg b/app/assets/svg/icons/flags/landscape/ug.svg new file mode 100644 index 000000000..520eee5c7 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ug.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/um.svg b/app/assets/svg/icons/flags/landscape/um.svg new file mode 100644 index 000000000..9e9eddaa4 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/um.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/un.svg b/app/assets/svg/icons/flags/landscape/un.svg new file mode 100644 index 000000000..632bbb4ac --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/un.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/us.svg b/app/assets/svg/icons/flags/landscape/us.svg new file mode 100644 index 000000000..9cfd0c927 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/us.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/uy.svg b/app/assets/svg/icons/flags/landscape/uy.svg new file mode 100644 index 000000000..62c36f8e5 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/uy.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/uz.svg b/app/assets/svg/icons/flags/landscape/uz.svg new file mode 100644 index 000000000..0ccca1b1b --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/uz.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/va.svg b/app/assets/svg/icons/flags/landscape/va.svg new file mode 100644 index 000000000..3e297d638 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/va.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/vc.svg b/app/assets/svg/icons/flags/landscape/vc.svg new file mode 100644 index 000000000..f26c2d8da --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/vc.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ve.svg b/app/assets/svg/icons/flags/landscape/ve.svg new file mode 100644 index 000000000..314e7f5f7 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ve.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/vg.svg b/app/assets/svg/icons/flags/landscape/vg.svg new file mode 100644 index 000000000..ac900888e --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/vg.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/vi.svg b/app/assets/svg/icons/flags/landscape/vi.svg new file mode 100644 index 000000000..d88d68f99 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/vi.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/vn.svg b/app/assets/svg/icons/flags/landscape/vn.svg new file mode 100644 index 000000000..7e4bac8f4 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/vn.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/vu.svg b/app/assets/svg/icons/flags/landscape/vu.svg new file mode 100644 index 000000000..326d29e9d --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/vu.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/wf.svg b/app/assets/svg/icons/flags/landscape/wf.svg new file mode 100644 index 000000000..054c57df9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/wf.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/ws.svg b/app/assets/svg/icons/flags/landscape/ws.svg new file mode 100644 index 000000000..0e758a7a9 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ws.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/xk.svg b/app/assets/svg/icons/flags/landscape/xk.svg new file mode 100644 index 000000000..0e8958d88 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/xk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/xx.svg b/app/assets/svg/icons/flags/landscape/xx.svg new file mode 100644 index 000000000..9333be363 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/xx.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/landscape/ye.svg b/app/assets/svg/icons/flags/landscape/ye.svg new file mode 100644 index 000000000..1c9e6d639 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/ye.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/yt.svg b/app/assets/svg/icons/flags/landscape/yt.svg new file mode 100644 index 000000000..e7776b307 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/yt.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/landscape/za.svg b/app/assets/svg/icons/flags/landscape/za.svg new file mode 100644 index 000000000..d563adb90 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/za.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/zm.svg b/app/assets/svg/icons/flags/landscape/zm.svg new file mode 100644 index 000000000..360f37aa1 --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/zm.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/landscape/zw.svg b/app/assets/svg/icons/flags/landscape/zw.svg new file mode 100644 index 000000000..93aac4f6c --- /dev/null +++ b/app/assets/svg/icons/flags/landscape/zw.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ad.svg b/app/assets/svg/icons/flags/square/ad.svg new file mode 100644 index 000000000..f10067ec6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ad.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ae.svg b/app/assets/svg/icons/flags/square/ae.svg new file mode 100644 index 000000000..b59e11352 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ae.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/af.svg b/app/assets/svg/icons/flags/square/af.svg new file mode 100644 index 000000000..9f382e0c6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/af.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ag.svg b/app/assets/svg/icons/flags/square/ag.svg new file mode 100644 index 000000000..9b951b6a5 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ag.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ai.svg b/app/assets/svg/icons/flags/square/ai.svg new file mode 100644 index 000000000..dfde89a9b --- /dev/null +++ b/app/assets/svg/icons/flags/square/ai.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/al.svg b/app/assets/svg/icons/flags/square/al.svg new file mode 100644 index 000000000..105679315 --- /dev/null +++ b/app/assets/svg/icons/flags/square/al.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/am.svg b/app/assets/svg/icons/flags/square/am.svg new file mode 100644 index 000000000..a188adfe4 --- /dev/null +++ b/app/assets/svg/icons/flags/square/am.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/ao.svg b/app/assets/svg/icons/flags/square/ao.svg new file mode 100644 index 000000000..067ffc423 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ao.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/aq.svg b/app/assets/svg/icons/flags/square/aq.svg new file mode 100644 index 000000000..28acee503 --- /dev/null +++ b/app/assets/svg/icons/flags/square/aq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/ar.svg b/app/assets/svg/icons/flags/square/ar.svg new file mode 100644 index 000000000..1cfbbd9e0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ar.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/arab.svg b/app/assets/svg/icons/flags/square/arab.svg new file mode 100644 index 000000000..aa7c958f3 --- /dev/null +++ b/app/assets/svg/icons/flags/square/arab.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/as.svg b/app/assets/svg/icons/flags/square/as.svg new file mode 100644 index 000000000..4c7a9bcf8 --- /dev/null +++ b/app/assets/svg/icons/flags/square/as.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/asean.svg b/app/assets/svg/icons/flags/square/asean.svg new file mode 100644 index 000000000..853614202 --- /dev/null +++ b/app/assets/svg/icons/flags/square/asean.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/at.svg b/app/assets/svg/icons/flags/square/at.svg new file mode 100644 index 000000000..758ced641 --- /dev/null +++ b/app/assets/svg/icons/flags/square/at.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/au.svg b/app/assets/svg/icons/flags/square/au.svg new file mode 100644 index 000000000..38bb24505 --- /dev/null +++ b/app/assets/svg/icons/flags/square/au.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/aw.svg b/app/assets/svg/icons/flags/square/aw.svg new file mode 100644 index 000000000..1f03d61a2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/aw.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ax.svg b/app/assets/svg/icons/flags/square/ax.svg new file mode 100644 index 000000000..481d2a33c --- /dev/null +++ b/app/assets/svg/icons/flags/square/ax.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/az.svg b/app/assets/svg/icons/flags/square/az.svg new file mode 100644 index 000000000..d692e2250 --- /dev/null +++ b/app/assets/svg/icons/flags/square/az.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ba.svg b/app/assets/svg/icons/flags/square/ba.svg new file mode 100644 index 000000000..456ca1236 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ba.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bb.svg b/app/assets/svg/icons/flags/square/bb.svg new file mode 100644 index 000000000..9a42841bf --- /dev/null +++ b/app/assets/svg/icons/flags/square/bb.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/bd.svg b/app/assets/svg/icons/flags/square/bd.svg new file mode 100644 index 000000000..86fcfbab0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bd.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/be.svg b/app/assets/svg/icons/flags/square/be.svg new file mode 100644 index 000000000..31d6210c7 --- /dev/null +++ b/app/assets/svg/icons/flags/square/be.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bf.svg b/app/assets/svg/icons/flags/square/bf.svg new file mode 100644 index 000000000..a5078df3f --- /dev/null +++ b/app/assets/svg/icons/flags/square/bf.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bg.svg b/app/assets/svg/icons/flags/square/bg.svg new file mode 100644 index 000000000..78412c5d2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/bh.svg b/app/assets/svg/icons/flags/square/bh.svg new file mode 100644 index 000000000..2d131aa59 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bh.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/bi.svg b/app/assets/svg/icons/flags/square/bi.svg new file mode 100644 index 000000000..36a0d3a68 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bi.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bj.svg b/app/assets/svg/icons/flags/square/bj.svg new file mode 100644 index 000000000..bb27414c0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bj.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bl.svg b/app/assets/svg/icons/flags/square/bl.svg new file mode 100644 index 000000000..65550d936 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bl.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bm.svg b/app/assets/svg/icons/flags/square/bm.svg new file mode 100644 index 000000000..0274d1450 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bm.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bn.svg b/app/assets/svg/icons/flags/square/bn.svg new file mode 100644 index 000000000..8cb06d197 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bn.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bo.svg b/app/assets/svg/icons/flags/square/bo.svg new file mode 100644 index 000000000..b4830eddf --- /dev/null +++ b/app/assets/svg/icons/flags/square/bo.svg @@ -0,0 +1,674 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bq.svg b/app/assets/svg/icons/flags/square/bq.svg new file mode 100644 index 000000000..4b9168e13 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/br.svg b/app/assets/svg/icons/flags/square/br.svg new file mode 100644 index 000000000..d6095d7b3 --- /dev/null +++ b/app/assets/svg/icons/flags/square/br.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bs.svg b/app/assets/svg/icons/flags/square/bs.svg new file mode 100644 index 000000000..0faa4bbac --- /dev/null +++ b/app/assets/svg/icons/flags/square/bs.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bt.svg b/app/assets/svg/icons/flags/square/bt.svg new file mode 100644 index 000000000..15eafc770 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bt.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bv.svg b/app/assets/svg/icons/flags/square/bv.svg new file mode 100644 index 000000000..dcc6ad106 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bv.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bw.svg b/app/assets/svg/icons/flags/square/bw.svg new file mode 100644 index 000000000..328e13c11 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bw.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/by.svg b/app/assets/svg/icons/flags/square/by.svg new file mode 100644 index 000000000..7d2ef67f1 --- /dev/null +++ b/app/assets/svg/icons/flags/square/by.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/bz.svg b/app/assets/svg/icons/flags/square/bz.svg new file mode 100644 index 000000000..913392ec2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/bz.svg @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ca.svg b/app/assets/svg/icons/flags/square/ca.svg new file mode 100644 index 000000000..1c0864c58 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ca.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/cc.svg b/app/assets/svg/icons/flags/square/cc.svg new file mode 100644 index 000000000..73fc80027 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cc.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cd.svg b/app/assets/svg/icons/flags/square/cd.svg new file mode 100644 index 000000000..ea1772873 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cd.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cefta.svg b/app/assets/svg/icons/flags/square/cefta.svg new file mode 100644 index 000000000..ff1a19bb6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cefta.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cf.svg b/app/assets/svg/icons/flags/square/cf.svg new file mode 100644 index 000000000..b0625db75 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cf.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cg.svg b/app/assets/svg/icons/flags/square/cg.svg new file mode 100644 index 000000000..f7868842f --- /dev/null +++ b/app/assets/svg/icons/flags/square/cg.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ch.svg b/app/assets/svg/icons/flags/square/ch.svg new file mode 100644 index 000000000..52578bfde --- /dev/null +++ b/app/assets/svg/icons/flags/square/ch.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ci.svg b/app/assets/svg/icons/flags/square/ci.svg new file mode 100644 index 000000000..2abf64119 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ci.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ck.svg b/app/assets/svg/icons/flags/square/ck.svg new file mode 100644 index 000000000..43a105763 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ck.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cl.svg b/app/assets/svg/icons/flags/square/cl.svg new file mode 100644 index 000000000..5fb6096b7 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cl.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cm.svg b/app/assets/svg/icons/flags/square/cm.svg new file mode 100644 index 000000000..ed4952b43 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cm.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cn.svg b/app/assets/svg/icons/flags/square/cn.svg new file mode 100644 index 000000000..e152f0166 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cn.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/co.svg b/app/assets/svg/icons/flags/square/co.svg new file mode 100644 index 000000000..5804bfe48 --- /dev/null +++ b/app/assets/svg/icons/flags/square/co.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cp.svg b/app/assets/svg/icons/flags/square/cp.svg new file mode 100644 index 000000000..ea3bfdcb4 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cp.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cr.svg b/app/assets/svg/icons/flags/square/cr.svg new file mode 100644 index 000000000..4e7889e22 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cr.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cu.svg b/app/assets/svg/icons/flags/square/cu.svg new file mode 100644 index 000000000..a28490235 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cu.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cv.svg b/app/assets/svg/icons/flags/square/cv.svg new file mode 100644 index 000000000..1170cd767 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cv.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cw.svg b/app/assets/svg/icons/flags/square/cw.svg new file mode 100644 index 000000000..57062abaa --- /dev/null +++ b/app/assets/svg/icons/flags/square/cw.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cx.svg b/app/assets/svg/icons/flags/square/cx.svg new file mode 100644 index 000000000..73c0240a2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/cx.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/cy.svg b/app/assets/svg/icons/flags/square/cy.svg new file mode 100644 index 000000000..3165d2dab --- /dev/null +++ b/app/assets/svg/icons/flags/square/cy.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/cz.svg b/app/assets/svg/icons/flags/square/cz.svg new file mode 100644 index 000000000..dcd0a6b1e --- /dev/null +++ b/app/assets/svg/icons/flags/square/cz.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/de.svg b/app/assets/svg/icons/flags/square/de.svg new file mode 100644 index 000000000..05a0a69ae --- /dev/null +++ b/app/assets/svg/icons/flags/square/de.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/dg.svg b/app/assets/svg/icons/flags/square/dg.svg new file mode 100644 index 000000000..8085a08a0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/dg.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/dj.svg b/app/assets/svg/icons/flags/square/dj.svg new file mode 100644 index 000000000..f5534d2a0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/dj.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/dk.svg b/app/assets/svg/icons/flags/square/dk.svg new file mode 100644 index 000000000..5aaaa1906 --- /dev/null +++ b/app/assets/svg/icons/flags/square/dk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/dm.svg b/app/assets/svg/icons/flags/square/dm.svg new file mode 100644 index 000000000..cb7c95867 --- /dev/null +++ b/app/assets/svg/icons/flags/square/dm.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/do.svg b/app/assets/svg/icons/flags/square/do.svg new file mode 100644 index 000000000..727d66908 --- /dev/null +++ b/app/assets/svg/icons/flags/square/do.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/dz.svg b/app/assets/svg/icons/flags/square/dz.svg new file mode 100644 index 000000000..8abcd258e --- /dev/null +++ b/app/assets/svg/icons/flags/square/dz.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/eac.svg b/app/assets/svg/icons/flags/square/eac.svg new file mode 100644 index 000000000..ee6905e26 --- /dev/null +++ b/app/assets/svg/icons/flags/square/eac.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ec.svg b/app/assets/svg/icons/flags/square/ec.svg new file mode 100644 index 000000000..e11e6ef25 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ec.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ee.svg b/app/assets/svg/icons/flags/square/ee.svg new file mode 100644 index 000000000..5a6a7e37e --- /dev/null +++ b/app/assets/svg/icons/flags/square/ee.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/eg.svg b/app/assets/svg/icons/flags/square/eg.svg new file mode 100644 index 000000000..0ce9c65cd --- /dev/null +++ b/app/assets/svg/icons/flags/square/eg.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/eh.svg b/app/assets/svg/icons/flags/square/eh.svg new file mode 100644 index 000000000..ae509fa8b --- /dev/null +++ b/app/assets/svg/icons/flags/square/eh.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/er.svg b/app/assets/svg/icons/flags/square/er.svg new file mode 100644 index 000000000..1a4891ef7 --- /dev/null +++ b/app/assets/svg/icons/flags/square/er.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/es-ct.svg b/app/assets/svg/icons/flags/square/es-ct.svg new file mode 100644 index 000000000..a06a2e3d3 --- /dev/null +++ b/app/assets/svg/icons/flags/square/es-ct.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/es-ga.svg b/app/assets/svg/icons/flags/square/es-ga.svg new file mode 100644 index 000000000..ccbb9f59c --- /dev/null +++ b/app/assets/svg/icons/flags/square/es-ga.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/es-pv.svg b/app/assets/svg/icons/flags/square/es-pv.svg new file mode 100644 index 000000000..7d383ed5e --- /dev/null +++ b/app/assets/svg/icons/flags/square/es-pv.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/es.svg b/app/assets/svg/icons/flags/square/es.svg new file mode 100644 index 000000000..6bfa092db --- /dev/null +++ b/app/assets/svg/icons/flags/square/es.svg @@ -0,0 +1,547 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/et.svg b/app/assets/svg/icons/flags/square/et.svg new file mode 100644 index 000000000..eb7f3c423 --- /dev/null +++ b/app/assets/svg/icons/flags/square/et.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/eu.svg b/app/assets/svg/icons/flags/square/eu.svg new file mode 100644 index 000000000..4a07fbe58 --- /dev/null +++ b/app/assets/svg/icons/flags/square/eu.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/fi.svg b/app/assets/svg/icons/flags/square/fi.svg new file mode 100644 index 000000000..aba2ef3b0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/fi.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/fj.svg b/app/assets/svg/icons/flags/square/fj.svg new file mode 100644 index 000000000..e1c44eed2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/fj.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/fk.svg b/app/assets/svg/icons/flags/square/fk.svg new file mode 100644 index 000000000..352eb5179 --- /dev/null +++ b/app/assets/svg/icons/flags/square/fk.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/fm.svg b/app/assets/svg/icons/flags/square/fm.svg new file mode 100644 index 000000000..4f7d31324 --- /dev/null +++ b/app/assets/svg/icons/flags/square/fm.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/fo.svg b/app/assets/svg/icons/flags/square/fo.svg new file mode 100644 index 000000000..eec994583 --- /dev/null +++ b/app/assets/svg/icons/flags/square/fo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/fr.svg b/app/assets/svg/icons/flags/square/fr.svg new file mode 100644 index 000000000..0f60170fc --- /dev/null +++ b/app/assets/svg/icons/flags/square/fr.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/ga.svg b/app/assets/svg/icons/flags/square/ga.svg new file mode 100644 index 000000000..113a5b58a --- /dev/null +++ b/app/assets/svg/icons/flags/square/ga.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gb-eng.svg b/app/assets/svg/icons/flags/square/gb-eng.svg new file mode 100644 index 000000000..ee48fed99 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gb-eng.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/gb-nir.svg b/app/assets/svg/icons/flags/square/gb-nir.svg new file mode 100644 index 000000000..b92e69f6f --- /dev/null +++ b/app/assets/svg/icons/flags/square/gb-nir.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gb-sct.svg b/app/assets/svg/icons/flags/square/gb-sct.svg new file mode 100644 index 000000000..44d38cc10 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gb-sct.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/gb-wls.svg b/app/assets/svg/icons/flags/square/gb-wls.svg new file mode 100644 index 000000000..5115b59c9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gb-wls.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gb.svg b/app/assets/svg/icons/flags/square/gb.svg new file mode 100644 index 000000000..ce4d1e000 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gb.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gd.svg b/app/assets/svg/icons/flags/square/gd.svg new file mode 100644 index 000000000..3159c67ea --- /dev/null +++ b/app/assets/svg/icons/flags/square/gd.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ge.svg b/app/assets/svg/icons/flags/square/ge.svg new file mode 100644 index 000000000..d3dc7290c --- /dev/null +++ b/app/assets/svg/icons/flags/square/ge.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/gf.svg b/app/assets/svg/icons/flags/square/gf.svg new file mode 100644 index 000000000..9cf5aa2b1 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gf.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/gg.svg b/app/assets/svg/icons/flags/square/gg.svg new file mode 100644 index 000000000..480f5503f --- /dev/null +++ b/app/assets/svg/icons/flags/square/gg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gh.svg b/app/assets/svg/icons/flags/square/gh.svg new file mode 100644 index 000000000..a64271b84 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gh.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/gi.svg b/app/assets/svg/icons/flags/square/gi.svg new file mode 100644 index 000000000..fe465ea25 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gi.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gl.svg b/app/assets/svg/icons/flags/square/gl.svg new file mode 100644 index 000000000..eaa817b1a --- /dev/null +++ b/app/assets/svg/icons/flags/square/gl.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/gm.svg b/app/assets/svg/icons/flags/square/gm.svg new file mode 100644 index 000000000..2a8f72443 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gm.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gn.svg b/app/assets/svg/icons/flags/square/gn.svg new file mode 100644 index 000000000..ae81f9d7b --- /dev/null +++ b/app/assets/svg/icons/flags/square/gn.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gp.svg b/app/assets/svg/icons/flags/square/gp.svg new file mode 100644 index 000000000..9dd8e3bba --- /dev/null +++ b/app/assets/svg/icons/flags/square/gp.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/gq.svg b/app/assets/svg/icons/flags/square/gq.svg new file mode 100644 index 000000000..3a991a19a --- /dev/null +++ b/app/assets/svg/icons/flags/square/gq.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gr.svg b/app/assets/svg/icons/flags/square/gr.svg new file mode 100644 index 000000000..a2688303a --- /dev/null +++ b/app/assets/svg/icons/flags/square/gr.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gs.svg b/app/assets/svg/icons/flags/square/gs.svg new file mode 100644 index 000000000..cf596f669 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gs.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gt.svg b/app/assets/svg/icons/flags/square/gt.svg new file mode 100644 index 000000000..b736d289c --- /dev/null +++ b/app/assets/svg/icons/flags/square/gt.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gu.svg b/app/assets/svg/icons/flags/square/gu.svg new file mode 100644 index 000000000..3f4d3daa2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gu.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gw.svg b/app/assets/svg/icons/flags/square/gw.svg new file mode 100644 index 000000000..61a054812 --- /dev/null +++ b/app/assets/svg/icons/flags/square/gw.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/gy.svg b/app/assets/svg/icons/flags/square/gy.svg new file mode 100644 index 000000000..35e2f08bb --- /dev/null +++ b/app/assets/svg/icons/flags/square/gy.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/hk.svg b/app/assets/svg/icons/flags/square/hk.svg new file mode 100644 index 000000000..eef02a18b --- /dev/null +++ b/app/assets/svg/icons/flags/square/hk.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/hm.svg b/app/assets/svg/icons/flags/square/hm.svg new file mode 100644 index 000000000..1f4d00704 --- /dev/null +++ b/app/assets/svg/icons/flags/square/hm.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/hn.svg b/app/assets/svg/icons/flags/square/hn.svg new file mode 100644 index 000000000..847df20c7 --- /dev/null +++ b/app/assets/svg/icons/flags/square/hn.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/hr.svg b/app/assets/svg/icons/flags/square/hr.svg new file mode 100644 index 000000000..d8719a440 --- /dev/null +++ b/app/assets/svg/icons/flags/square/hr.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ht.svg b/app/assets/svg/icons/flags/square/ht.svg new file mode 100644 index 000000000..101bd593c --- /dev/null +++ b/app/assets/svg/icons/flags/square/ht.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/hu.svg b/app/assets/svg/icons/flags/square/hu.svg new file mode 100644 index 000000000..088242d93 --- /dev/null +++ b/app/assets/svg/icons/flags/square/hu.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ic.svg b/app/assets/svg/icons/flags/square/ic.svg new file mode 100644 index 000000000..096603d4b --- /dev/null +++ b/app/assets/svg/icons/flags/square/ic.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/id.svg b/app/assets/svg/icons/flags/square/id.svg new file mode 100644 index 000000000..df0801815 --- /dev/null +++ b/app/assets/svg/icons/flags/square/id.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/ie.svg b/app/assets/svg/icons/flags/square/ie.svg new file mode 100644 index 000000000..e13de22df --- /dev/null +++ b/app/assets/svg/icons/flags/square/ie.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/il.svg b/app/assets/svg/icons/flags/square/il.svg new file mode 100644 index 000000000..0a2a6d99b --- /dev/null +++ b/app/assets/svg/icons/flags/square/il.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/im.svg b/app/assets/svg/icons/flags/square/im.svg new file mode 100644 index 000000000..05c3fa464 --- /dev/null +++ b/app/assets/svg/icons/flags/square/im.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/in.svg b/app/assets/svg/icons/flags/square/in.svg new file mode 100644 index 000000000..26a02cff0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/in.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/io.svg b/app/assets/svg/icons/flags/square/io.svg new file mode 100644 index 000000000..9ce776aab --- /dev/null +++ b/app/assets/svg/icons/flags/square/io.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/iq.svg b/app/assets/svg/icons/flags/square/iq.svg new file mode 100644 index 000000000..d354c990a --- /dev/null +++ b/app/assets/svg/icons/flags/square/iq.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ir.svg b/app/assets/svg/icons/flags/square/ir.svg new file mode 100644 index 000000000..66537b614 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ir.svg @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/is.svg b/app/assets/svg/icons/flags/square/is.svg new file mode 100644 index 000000000..26510b99e --- /dev/null +++ b/app/assets/svg/icons/flags/square/is.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/it.svg b/app/assets/svg/icons/flags/square/it.svg new file mode 100644 index 000000000..b9596d050 --- /dev/null +++ b/app/assets/svg/icons/flags/square/it.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/je.svg b/app/assets/svg/icons/flags/square/je.svg new file mode 100644 index 000000000..52c66458a --- /dev/null +++ b/app/assets/svg/icons/flags/square/je.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/jm.svg b/app/assets/svg/icons/flags/square/jm.svg new file mode 100644 index 000000000..07f023c79 --- /dev/null +++ b/app/assets/svg/icons/flags/square/jm.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/jo.svg b/app/assets/svg/icons/flags/square/jo.svg new file mode 100644 index 000000000..fbbd68104 --- /dev/null +++ b/app/assets/svg/icons/flags/square/jo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/jp.svg b/app/assets/svg/icons/flags/square/jp.svg new file mode 100644 index 000000000..118686a0e --- /dev/null +++ b/app/assets/svg/icons/flags/square/jp.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ke.svg b/app/assets/svg/icons/flags/square/ke.svg new file mode 100644 index 000000000..09168c2a9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ke.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/kg.svg b/app/assets/svg/icons/flags/square/kg.svg new file mode 100644 index 000000000..732b2f1a6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/kg.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/kh.svg b/app/assets/svg/icons/flags/square/kh.svg new file mode 100644 index 000000000..567577a26 --- /dev/null +++ b/app/assets/svg/icons/flags/square/kh.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ki.svg b/app/assets/svg/icons/flags/square/ki.svg new file mode 100644 index 000000000..02d7569c9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ki.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/km.svg b/app/assets/svg/icons/flags/square/km.svg new file mode 100644 index 000000000..b19fd10c0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/km.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/kn.svg b/app/assets/svg/icons/flags/square/kn.svg new file mode 100644 index 000000000..42d5adfe5 --- /dev/null +++ b/app/assets/svg/icons/flags/square/kn.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/kp.svg b/app/assets/svg/icons/flags/square/kp.svg new file mode 100644 index 000000000..67f33382a --- /dev/null +++ b/app/assets/svg/icons/flags/square/kp.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/kr.svg b/app/assets/svg/icons/flags/square/kr.svg new file mode 100644 index 000000000..af3d35eb5 --- /dev/null +++ b/app/assets/svg/icons/flags/square/kr.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/kw.svg b/app/assets/svg/icons/flags/square/kw.svg new file mode 100644 index 000000000..b2fe54faa --- /dev/null +++ b/app/assets/svg/icons/flags/square/kw.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ky.svg b/app/assets/svg/icons/flags/square/ky.svg new file mode 100644 index 000000000..72e516431 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ky.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/kz.svg b/app/assets/svg/icons/flags/square/kz.svg new file mode 100644 index 000000000..c65c5d582 --- /dev/null +++ b/app/assets/svg/icons/flags/square/kz.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/la.svg b/app/assets/svg/icons/flags/square/la.svg new file mode 100644 index 000000000..af70d0dcc --- /dev/null +++ b/app/assets/svg/icons/flags/square/la.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/lb.svg b/app/assets/svg/icons/flags/square/lb.svg new file mode 100644 index 000000000..a5ffc76cf --- /dev/null +++ b/app/assets/svg/icons/flags/square/lb.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/lc.svg b/app/assets/svg/icons/flags/square/lc.svg new file mode 100644 index 000000000..aa18fac83 --- /dev/null +++ b/app/assets/svg/icons/flags/square/lc.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/li.svg b/app/assets/svg/icons/flags/square/li.svg new file mode 100644 index 000000000..436dfc52e --- /dev/null +++ b/app/assets/svg/icons/flags/square/li.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/lk.svg b/app/assets/svg/icons/flags/square/lk.svg new file mode 100644 index 000000000..2ac818395 --- /dev/null +++ b/app/assets/svg/icons/flags/square/lk.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/lr.svg b/app/assets/svg/icons/flags/square/lr.svg new file mode 100644 index 000000000..74382abbe --- /dev/null +++ b/app/assets/svg/icons/flags/square/lr.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ls.svg b/app/assets/svg/icons/flags/square/ls.svg new file mode 100644 index 000000000..605c087af --- /dev/null +++ b/app/assets/svg/icons/flags/square/ls.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/lt.svg b/app/assets/svg/icons/flags/square/lt.svg new file mode 100644 index 000000000..52ada948c --- /dev/null +++ b/app/assets/svg/icons/flags/square/lt.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/lu.svg b/app/assets/svg/icons/flags/square/lu.svg new file mode 100644 index 000000000..037c31524 --- /dev/null +++ b/app/assets/svg/icons/flags/square/lu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/lv.svg b/app/assets/svg/icons/flags/square/lv.svg new file mode 100644 index 000000000..5af883c70 --- /dev/null +++ b/app/assets/svg/icons/flags/square/lv.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/ly.svg b/app/assets/svg/icons/flags/square/ly.svg new file mode 100644 index 000000000..4375a9eaf --- /dev/null +++ b/app/assets/svg/icons/flags/square/ly.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ma.svg b/app/assets/svg/icons/flags/square/ma.svg new file mode 100644 index 000000000..804166728 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ma.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/mc.svg b/app/assets/svg/icons/flags/square/mc.svg new file mode 100644 index 000000000..04173a415 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mc.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/md.svg b/app/assets/svg/icons/flags/square/md.svg new file mode 100644 index 000000000..f204511cb --- /dev/null +++ b/app/assets/svg/icons/flags/square/md.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/me.svg b/app/assets/svg/icons/flags/square/me.svg new file mode 100644 index 000000000..25c6b28ac --- /dev/null +++ b/app/assets/svg/icons/flags/square/me.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mf.svg b/app/assets/svg/icons/flags/square/mf.svg new file mode 100644 index 000000000..8d3285b86 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mf.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/mg.svg b/app/assets/svg/icons/flags/square/mg.svg new file mode 100644 index 000000000..4f901cad0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mg.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mh.svg b/app/assets/svg/icons/flags/square/mh.svg new file mode 100644 index 000000000..1db268d22 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mh.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mk.svg b/app/assets/svg/icons/flags/square/mk.svg new file mode 100644 index 000000000..0ee923a35 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/ml.svg b/app/assets/svg/icons/flags/square/ml.svg new file mode 100644 index 000000000..665d6b243 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ml.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mm.svg b/app/assets/svg/icons/flags/square/mm.svg new file mode 100644 index 000000000..391f0c70b --- /dev/null +++ b/app/assets/svg/icons/flags/square/mm.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mn.svg b/app/assets/svg/icons/flags/square/mn.svg new file mode 100644 index 000000000..0df52110c --- /dev/null +++ b/app/assets/svg/icons/flags/square/mn.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mo.svg b/app/assets/svg/icons/flags/square/mo.svg new file mode 100644 index 000000000..50624d717 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mp.svg b/app/assets/svg/icons/flags/square/mp.svg new file mode 100644 index 000000000..27e8980fa --- /dev/null +++ b/app/assets/svg/icons/flags/square/mp.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mq.svg b/app/assets/svg/icons/flags/square/mq.svg new file mode 100644 index 000000000..dcf005443 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/mr.svg b/app/assets/svg/icons/flags/square/mr.svg new file mode 100644 index 000000000..d06c5b896 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mr.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/ms.svg b/app/assets/svg/icons/flags/square/ms.svg new file mode 100644 index 000000000..53baf7c34 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ms.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mt.svg b/app/assets/svg/icons/flags/square/mt.svg new file mode 100644 index 000000000..bcc01dde2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mt.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mu.svg b/app/assets/svg/icons/flags/square/mu.svg new file mode 100644 index 000000000..2afe1d384 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mu.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mv.svg b/app/assets/svg/icons/flags/square/mv.svg new file mode 100644 index 000000000..c9a6c5bcc --- /dev/null +++ b/app/assets/svg/icons/flags/square/mv.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/mw.svg b/app/assets/svg/icons/flags/square/mw.svg new file mode 100644 index 000000000..576ba8cc9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mw.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mx.svg b/app/assets/svg/icons/flags/square/mx.svg new file mode 100644 index 000000000..2b371e779 --- /dev/null +++ b/app/assets/svg/icons/flags/square/mx.svg @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/my.svg b/app/assets/svg/icons/flags/square/my.svg new file mode 100644 index 000000000..4f62c7d54 --- /dev/null +++ b/app/assets/svg/icons/flags/square/my.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/mz.svg b/app/assets/svg/icons/flags/square/mz.svg new file mode 100644 index 000000000..e1e15694d --- /dev/null +++ b/app/assets/svg/icons/flags/square/mz.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/na.svg b/app/assets/svg/icons/flags/square/na.svg new file mode 100644 index 000000000..36ac8d77e --- /dev/null +++ b/app/assets/svg/icons/flags/square/na.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/nc.svg b/app/assets/svg/icons/flags/square/nc.svg new file mode 100644 index 000000000..6226ebcc1 --- /dev/null +++ b/app/assets/svg/icons/flags/square/nc.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ne.svg b/app/assets/svg/icons/flags/square/ne.svg new file mode 100644 index 000000000..a96b027ab --- /dev/null +++ b/app/assets/svg/icons/flags/square/ne.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/nf.svg b/app/assets/svg/icons/flags/square/nf.svg new file mode 100644 index 000000000..c9e57436d --- /dev/null +++ b/app/assets/svg/icons/flags/square/nf.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ng.svg b/app/assets/svg/icons/flags/square/ng.svg new file mode 100644 index 000000000..62813e861 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ng.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/ni.svg b/app/assets/svg/icons/flags/square/ni.svg new file mode 100644 index 000000000..7ea3eb6a8 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ni.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/nl.svg b/app/assets/svg/icons/flags/square/nl.svg new file mode 100644 index 000000000..49ca5bc00 --- /dev/null +++ b/app/assets/svg/icons/flags/square/nl.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/no.svg b/app/assets/svg/icons/flags/square/no.svg new file mode 100644 index 000000000..939920d40 --- /dev/null +++ b/app/assets/svg/icons/flags/square/no.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/np.svg b/app/assets/svg/icons/flags/square/np.svg new file mode 100644 index 000000000..f0e0b5daa --- /dev/null +++ b/app/assets/svg/icons/flags/square/np.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/nr.svg b/app/assets/svg/icons/flags/square/nr.svg new file mode 100644 index 000000000..c8c827e70 --- /dev/null +++ b/app/assets/svg/icons/flags/square/nr.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/nu.svg b/app/assets/svg/icons/flags/square/nu.svg new file mode 100644 index 000000000..ce316723d --- /dev/null +++ b/app/assets/svg/icons/flags/square/nu.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/nz.svg b/app/assets/svg/icons/flags/square/nz.svg new file mode 100644 index 000000000..ee617d6f2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/nz.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/om.svg b/app/assets/svg/icons/flags/square/om.svg new file mode 100644 index 000000000..038631fed --- /dev/null +++ b/app/assets/svg/icons/flags/square/om.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/pa.svg b/app/assets/svg/icons/flags/square/pa.svg new file mode 100644 index 000000000..108c40bff --- /dev/null +++ b/app/assets/svg/icons/flags/square/pa.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/pc.svg b/app/assets/svg/icons/flags/square/pc.svg new file mode 100644 index 000000000..e0d561b1e --- /dev/null +++ b/app/assets/svg/icons/flags/square/pc.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/pe.svg b/app/assets/svg/icons/flags/square/pe.svg new file mode 100644 index 000000000..9ba4c6124 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pe.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/pf.svg b/app/assets/svg/icons/flags/square/pf.svg new file mode 100644 index 000000000..2580dd2f2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pf.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/pg.svg b/app/assets/svg/icons/flags/square/pg.svg new file mode 100644 index 000000000..1b6e536e8 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pg.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ph.svg b/app/assets/svg/icons/flags/square/ph.svg new file mode 100644 index 000000000..390f1fd84 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ph.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/pk.svg b/app/assets/svg/icons/flags/square/pk.svg new file mode 100644 index 000000000..1a573af6e --- /dev/null +++ b/app/assets/svg/icons/flags/square/pk.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/pl.svg b/app/assets/svg/icons/flags/square/pl.svg new file mode 100644 index 000000000..8c43577b0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pl.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/pm.svg b/app/assets/svg/icons/flags/square/pm.svg new file mode 100644 index 000000000..950c6e8c0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pm.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/pn.svg b/app/assets/svg/icons/flags/square/pn.svg new file mode 100644 index 000000000..886abca8a --- /dev/null +++ b/app/assets/svg/icons/flags/square/pn.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/pr.svg b/app/assets/svg/icons/flags/square/pr.svg new file mode 100644 index 000000000..eb302ad45 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pr.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ps.svg b/app/assets/svg/icons/flags/square/ps.svg new file mode 100644 index 000000000..5d28cc84b --- /dev/null +++ b/app/assets/svg/icons/flags/square/ps.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/pt.svg b/app/assets/svg/icons/flags/square/pt.svg new file mode 100644 index 000000000..6c8334b62 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pt.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/pw.svg b/app/assets/svg/icons/flags/square/pw.svg new file mode 100644 index 000000000..ef6be7983 --- /dev/null +++ b/app/assets/svg/icons/flags/square/pw.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/py.svg b/app/assets/svg/icons/flags/square/py.svg new file mode 100644 index 000000000..107bd1d81 --- /dev/null +++ b/app/assets/svg/icons/flags/square/py.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/qa.svg b/app/assets/svg/icons/flags/square/qa.svg new file mode 100644 index 000000000..897a21bca --- /dev/null +++ b/app/assets/svg/icons/flags/square/qa.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/re.svg b/app/assets/svg/icons/flags/square/re.svg new file mode 100644 index 000000000..41d87d938 --- /dev/null +++ b/app/assets/svg/icons/flags/square/re.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ro.svg b/app/assets/svg/icons/flags/square/ro.svg new file mode 100644 index 000000000..e6cf0f6e1 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ro.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/rs.svg b/app/assets/svg/icons/flags/square/rs.svg new file mode 100644 index 000000000..3610fd18e --- /dev/null +++ b/app/assets/svg/icons/flags/square/rs.svg @@ -0,0 +1,296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ru.svg b/app/assets/svg/icons/flags/square/ru.svg new file mode 100644 index 000000000..f428b0ccb --- /dev/null +++ b/app/assets/svg/icons/flags/square/ru.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/rw.svg b/app/assets/svg/icons/flags/square/rw.svg new file mode 100644 index 000000000..3d484fd90 --- /dev/null +++ b/app/assets/svg/icons/flags/square/rw.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sa.svg b/app/assets/svg/icons/flags/square/sa.svg new file mode 100644 index 000000000..8bf5eda1b --- /dev/null +++ b/app/assets/svg/icons/flags/square/sa.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sb.svg b/app/assets/svg/icons/flags/square/sb.svg new file mode 100644 index 000000000..398c70847 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sb.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sc.svg b/app/assets/svg/icons/flags/square/sc.svg new file mode 100644 index 000000000..2996bac45 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sc.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sd.svg b/app/assets/svg/icons/flags/square/sd.svg new file mode 100644 index 000000000..0b9abdc8a --- /dev/null +++ b/app/assets/svg/icons/flags/square/sd.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/se.svg b/app/assets/svg/icons/flags/square/se.svg new file mode 100644 index 000000000..8f3f134d2 --- /dev/null +++ b/app/assets/svg/icons/flags/square/se.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/sg.svg b/app/assets/svg/icons/flags/square/sg.svg new file mode 100644 index 000000000..60625e97f --- /dev/null +++ b/app/assets/svg/icons/flags/square/sg.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sh-ac.svg b/app/assets/svg/icons/flags/square/sh-ac.svg new file mode 100644 index 000000000..5f82d6618 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sh-ac.svg @@ -0,0 +1,690 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sh-hl.svg b/app/assets/svg/icons/flags/square/sh-hl.svg new file mode 100644 index 000000000..179fed69d --- /dev/null +++ b/app/assets/svg/icons/flags/square/sh-hl.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sh-ta.svg b/app/assets/svg/icons/flags/square/sh-ta.svg new file mode 100644 index 000000000..619301bb0 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sh-ta.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sh.svg b/app/assets/svg/icons/flags/square/sh.svg new file mode 100644 index 000000000..2fd372750 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sh.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/si.svg b/app/assets/svg/icons/flags/square/si.svg new file mode 100644 index 000000000..ba67e1924 --- /dev/null +++ b/app/assets/svg/icons/flags/square/si.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sj.svg b/app/assets/svg/icons/flags/square/sj.svg new file mode 100644 index 000000000..ecb9c796b --- /dev/null +++ b/app/assets/svg/icons/flags/square/sj.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sk.svg b/app/assets/svg/icons/flags/square/sk.svg new file mode 100644 index 000000000..484612740 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sk.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sl.svg b/app/assets/svg/icons/flags/square/sl.svg new file mode 100644 index 000000000..b649f1bd5 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sl.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sm.svg b/app/assets/svg/icons/flags/square/sm.svg new file mode 100644 index 000000000..7fe8b1464 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sm.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sn.svg b/app/assets/svg/icons/flags/square/sn.svg new file mode 100644 index 000000000..ff9cf2eb3 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sn.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/so.svg b/app/assets/svg/icons/flags/square/so.svg new file mode 100644 index 000000000..4848dbe0b --- /dev/null +++ b/app/assets/svg/icons/flags/square/so.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sr.svg b/app/assets/svg/icons/flags/square/sr.svg new file mode 100644 index 000000000..0ca359627 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sr.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/ss.svg b/app/assets/svg/icons/flags/square/ss.svg new file mode 100644 index 000000000..bb50fac15 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ss.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/st.svg b/app/assets/svg/icons/flags/square/st.svg new file mode 100644 index 000000000..c5e7c5ce6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/st.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sv.svg b/app/assets/svg/icons/flags/square/sv.svg new file mode 100644 index 000000000..110f78de7 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sv.svg @@ -0,0 +1,593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sx.svg b/app/assets/svg/icons/flags/square/sx.svg new file mode 100644 index 000000000..fbf74681f --- /dev/null +++ b/app/assets/svg/icons/flags/square/sx.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/sy.svg b/app/assets/svg/icons/flags/square/sy.svg new file mode 100644 index 000000000..b2fdc2fe6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sy.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/sz.svg b/app/assets/svg/icons/flags/square/sz.svg new file mode 100644 index 000000000..bd5e237d9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/sz.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tc.svg b/app/assets/svg/icons/flags/square/tc.svg new file mode 100644 index 000000000..52a24526e --- /dev/null +++ b/app/assets/svg/icons/flags/square/tc.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/td.svg b/app/assets/svg/icons/flags/square/td.svg new file mode 100644 index 000000000..8201312b6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/td.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tf.svg b/app/assets/svg/icons/flags/square/tf.svg new file mode 100644 index 000000000..1ab7f6a8f --- /dev/null +++ b/app/assets/svg/icons/flags/square/tf.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tg.svg b/app/assets/svg/icons/flags/square/tg.svg new file mode 100644 index 000000000..6ed03c5db --- /dev/null +++ b/app/assets/svg/icons/flags/square/tg.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/th.svg b/app/assets/svg/icons/flags/square/th.svg new file mode 100644 index 000000000..35141d39a --- /dev/null +++ b/app/assets/svg/icons/flags/square/th.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tj.svg b/app/assets/svg/icons/flags/square/tj.svg new file mode 100644 index 000000000..9232ec1d3 --- /dev/null +++ b/app/assets/svg/icons/flags/square/tj.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tk.svg b/app/assets/svg/icons/flags/square/tk.svg new file mode 100644 index 000000000..9ff92e5ee --- /dev/null +++ b/app/assets/svg/icons/flags/square/tk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/tl.svg b/app/assets/svg/icons/flags/square/tl.svg new file mode 100644 index 000000000..4fbb245e9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/tl.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tm.svg b/app/assets/svg/icons/flags/square/tm.svg new file mode 100644 index 000000000..0272d71bb --- /dev/null +++ b/app/assets/svg/icons/flags/square/tm.svg @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tn.svg b/app/assets/svg/icons/flags/square/tn.svg new file mode 100644 index 000000000..ab3e36e4b --- /dev/null +++ b/app/assets/svg/icons/flags/square/tn.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/to.svg b/app/assets/svg/icons/flags/square/to.svg new file mode 100644 index 000000000..3f1b60079 --- /dev/null +++ b/app/assets/svg/icons/flags/square/to.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tr.svg b/app/assets/svg/icons/flags/square/tr.svg new file mode 100644 index 000000000..0fe9017c9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/tr.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tt.svg b/app/assets/svg/icons/flags/square/tt.svg new file mode 100644 index 000000000..0f7f26e7e --- /dev/null +++ b/app/assets/svg/icons/flags/square/tt.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tv.svg b/app/assets/svg/icons/flags/square/tv.svg new file mode 100644 index 000000000..098b91610 --- /dev/null +++ b/app/assets/svg/icons/flags/square/tv.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tw.svg b/app/assets/svg/icons/flags/square/tw.svg new file mode 100644 index 000000000..83f4e442e --- /dev/null +++ b/app/assets/svg/icons/flags/square/tw.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/tz.svg b/app/assets/svg/icons/flags/square/tz.svg new file mode 100644 index 000000000..846cbb5ad --- /dev/null +++ b/app/assets/svg/icons/flags/square/tz.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ua.svg b/app/assets/svg/icons/flags/square/ua.svg new file mode 100644 index 000000000..7ceb89463 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ua.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/assets/svg/icons/flags/square/ug.svg b/app/assets/svg/icons/flags/square/ug.svg new file mode 100644 index 000000000..fd377dfa5 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ug.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/um.svg b/app/assets/svg/icons/flags/square/um.svg new file mode 100644 index 000000000..b8d4502e6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/um.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/un.svg b/app/assets/svg/icons/flags/square/un.svg new file mode 100644 index 000000000..fc75c9136 --- /dev/null +++ b/app/assets/svg/icons/flags/square/un.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/us.svg b/app/assets/svg/icons/flags/square/us.svg new file mode 100644 index 000000000..a7220476a --- /dev/null +++ b/app/assets/svg/icons/flags/square/us.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/uy.svg b/app/assets/svg/icons/flags/square/uy.svg new file mode 100644 index 000000000..f6b08b280 --- /dev/null +++ b/app/assets/svg/icons/flags/square/uy.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/uz.svg b/app/assets/svg/icons/flags/square/uz.svg new file mode 100644 index 000000000..3385bc5aa --- /dev/null +++ b/app/assets/svg/icons/flags/square/uz.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/va.svg b/app/assets/svg/icons/flags/square/va.svg new file mode 100644 index 000000000..04e6d50a9 --- /dev/null +++ b/app/assets/svg/icons/flags/square/va.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/vc.svg b/app/assets/svg/icons/flags/square/vc.svg new file mode 100644 index 000000000..21d41a805 --- /dev/null +++ b/app/assets/svg/icons/flags/square/vc.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/ve.svg b/app/assets/svg/icons/flags/square/ve.svg new file mode 100644 index 000000000..665135ba6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ve.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/vg.svg b/app/assets/svg/icons/flags/square/vg.svg new file mode 100644 index 000000000..31fcae34b --- /dev/null +++ b/app/assets/svg/icons/flags/square/vg.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/vi.svg b/app/assets/svg/icons/flags/square/vi.svg new file mode 100644 index 000000000..4509ac955 --- /dev/null +++ b/app/assets/svg/icons/flags/square/vi.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/vn.svg b/app/assets/svg/icons/flags/square/vn.svg new file mode 100644 index 000000000..49a68f02e --- /dev/null +++ b/app/assets/svg/icons/flags/square/vn.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/vu.svg b/app/assets/svg/icons/flags/square/vu.svg new file mode 100644 index 000000000..3dbcf958f --- /dev/null +++ b/app/assets/svg/icons/flags/square/vu.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/wf.svg b/app/assets/svg/icons/flags/square/wf.svg new file mode 100644 index 000000000..5ba64e4da --- /dev/null +++ b/app/assets/svg/icons/flags/square/wf.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/ws.svg b/app/assets/svg/icons/flags/square/ws.svg new file mode 100644 index 000000000..ab08fdb91 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ws.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/xk.svg b/app/assets/svg/icons/flags/square/xk.svg new file mode 100644 index 000000000..b5403e39f --- /dev/null +++ b/app/assets/svg/icons/flags/square/xk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/xx.svg b/app/assets/svg/icons/flags/square/xx.svg new file mode 100644 index 000000000..5a44cb701 --- /dev/null +++ b/app/assets/svg/icons/flags/square/xx.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/svg/icons/flags/square/ye.svg b/app/assets/svg/icons/flags/square/ye.svg new file mode 100644 index 000000000..2ccb23bf6 --- /dev/null +++ b/app/assets/svg/icons/flags/square/ye.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/assets/svg/icons/flags/square/yt.svg b/app/assets/svg/icons/flags/square/yt.svg new file mode 100644 index 000000000..41a4408cb --- /dev/null +++ b/app/assets/svg/icons/flags/square/yt.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/assets/svg/icons/flags/square/za.svg b/app/assets/svg/icons/flags/square/za.svg new file mode 100644 index 000000000..397696eda --- /dev/null +++ b/app/assets/svg/icons/flags/square/za.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/zm.svg b/app/assets/svg/icons/flags/square/zm.svg new file mode 100644 index 000000000..9b2060178 --- /dev/null +++ b/app/assets/svg/icons/flags/square/zm.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/svg/icons/flags/square/zw.svg b/app/assets/svg/icons/flags/square/zw.svg new file mode 100644 index 000000000..f9f65eebc --- /dev/null +++ b/app/assets/svg/icons/flags/square/zw.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/controllers/api/v1/notes_controller.rb b/app/controllers/api/v1/notes_controller.rb new file mode 100644 index 000000000..873e1e95c --- /dev/null +++ b/app/controllers/api/v1/notes_controller.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +class Api::V1::NotesController < ApiController + before_action :set_note, only: %i[show update destroy] + + def index + notes = current_api_user.notes + + notes = notes.where(attachable_type: params[:attachable_type]) if params[:attachable_type].present? + notes = notes.where(attachable_id: params[:attachable_id]) if params[:attachable_id].present? + notes = notes.standalone if params[:standalone] == 'true' + + render json: notes.ordered.map { Api::NoteSerializer.new(_1).call }, status: :ok + end + + def show + render json: Api::NoteSerializer.new(@note).call, status: :ok + end + + def create + @note = current_api_user.notes.build(note_params) + + if @note.save + render json: Api::NoteSerializer.new(@note).call, status: :created + else + render json: { errors: @note.errors.full_messages }, status: :unprocessable_content + end + end + + def update + if @note.update(note_params) + render json: Api::NoteSerializer.new(@note).call, status: :ok + else + render json: { errors: @note.errors.full_messages }, status: :unprocessable_content + end + end + + def destroy + @note.destroy! + + render json: { message: 'Note was successfully deleted' }, status: :ok + end + + private + + def set_note + @note = current_api_user.notes.find(params[:id]) + end + + def note_params + params.require(:note).permit(:title, :body, :latitude, :longitude, :attachable_type, + :attachable_id, :noted_at) + end +end diff --git a/app/controllers/trips/notes_controller.rb b/app/controllers/trips/notes_controller.rb new file mode 100644 index 000000000..a55bd25a5 --- /dev/null +++ b/app/controllers/trips/notes_controller.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module Trips + class NotesController < ApplicationController + before_action :authenticate_user! + before_action :set_trip + before_action :set_note, only: %i[update destroy] + + def create + date = note_params[:date].to_date + @note = @trip.notes.for_date(date).first || @trip.notes.build(noted_at: date.to_datetime.noon) + @note.user = current_user + @note.body = note_params[:body] + + if @note.save + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "note-#{@trip.id}-#{@note.date}", + partial: 'trips/notes/note', + locals: { note: @note, trip: @trip } + ) + end + format.html { redirect_to @trip } + end + else + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "note-#{@trip.id}-#{note_params[:date]}", + partial: 'trips/notes/form', + locals: { note: @note, trip: @trip } + ) + end + format.html { redirect_to @trip, alert: @note.errors.full_messages.join(', ') } + end + end + end + + def update + if @note.update(body: note_params[:body]) + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "note-#{@trip.id}-#{@note.date}", + partial: 'trips/notes/note', + locals: { note: @note, trip: @trip } + ) + end + format.html { redirect_to @trip } + end + else + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "note-#{@trip.id}-#{@note.date}", + partial: 'trips/notes/form', + locals: { note: @note, trip: @trip } + ) + end + format.html { redirect_to @trip, alert: @note.errors.full_messages.join(', ') } + end + end + end + + def destroy + date = @note.date + @note.destroy! + + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "note-#{@trip.id}-#{date}", + partial: 'trips/notes/empty', + locals: { trip: @trip, date: date } + ) + end + format.html { redirect_to @trip } + end + end + + private + + def set_trip + @trip = current_user.trips.find(params[:trip_id]) + end + + def set_note + @note = @trip.notes.find(params[:id]) + end + + def note_params + params.require(:note).permit(:date, :body) + end + end +end diff --git a/app/controllers/trips_controller.rb b/app/controllers/trips_controller.rb index 8c524c833..bb1f5e694 100644 --- a/app/controllers/trips_controller.rb +++ b/app/controllers/trips_controller.rb @@ -13,10 +13,14 @@ def index def show @photo_previews = @trip.photo_previews @photo_sources = @trip.photo_sources + @distance_unit = current_user.safe_settings.distance_unit + @timezone = current_user.timezone + @day_notes = @trip.notes.index_by(&:date) + @day_stats = compute_day_stats return unless @trip.path.blank? || @trip.distance.blank? || @trip.visited_countries.blank? - Trips::CalculateAllJob.perform_later(@trip.id, current_user.safe_settings.distance_unit) + Trips::CalculateAllJob.perform_later(@trip.id, @distance_unit) end def new @@ -63,6 +67,30 @@ def set_coordinates end def trip_params - params.require(:trip).permit(:name, :started_at, :ended_at, :notes) + params.require(:trip).permit(:name, :started_at, :ended_at, :description) + end + + def compute_day_stats + cache_key = "trip_day_stats/#{@trip.id}/#{@trip.updated_at.to_i}/#{@timezone}" + + Rails.cache.fetch(cache_key, expires_in: 1.hour) do + points_data = @trip.points.order(:timestamp) + .pluck(Arel.sql('ST_Y(lonlat::geometry)'), Arel.sql('ST_X(lonlat::geometry)'), :timestamp) + next {} if points_data.empty? + + points_data.group_by { |_, _, ts| Time.at(ts).in_time_zone(@timezone).to_date }.transform_values do |pts| + first_time = Time.at(pts.first[2]).in_time_zone(@timezone) + last_time = Time.at(pts.last[2]).in_time_zone(@timezone) + + distance_m = 0.0 + pts.each_cons(2) do |(lat1, lon1, _), (lat2, lon2, _)| + distance_m += Geocoder::Calculations.distance_between( + [lat1.to_f, lon1.to_f], [lat2.to_f, lon2.to_f], units: :km + ) * 1000 + end + + { first_time: first_time, last_time: last_time, distance_m: distance_m } + end + end end end diff --git a/app/helpers/country_flag_helper.rb b/app/helpers/country_flag_helper.rb index 912a1a537..adb3338ca 100644 --- a/app/helpers/country_flag_helper.rb +++ b/app/helpers/country_flag_helper.rb @@ -1,14 +1,41 @@ # frozen_string_literal: true module CountryFlagHelper + # User-assigned codes for territories with iso_a2 = "-99" in Natural Earth data. + # Only includes territories that have a corresponding flag SVG in flag-icons. + TERRITORY_CODES = { + 'Kosovo' => 'XK', + 'Somaliland' => 'SO', + 'Northern Cyprus' => 'CY', + 'Dhekelia Sovereign Base Area' => 'GB', + 'Akrotiri Sovereign Base Area' => 'GB', + 'US Naval Base Guantanamo Bay' => 'US', + 'Cyprus No Mans Area' => 'CY', + 'Baykonur Cosmodrome' => 'KZ', + 'Brazilian Island' => 'BR', + 'Indian Ocean Territories' => 'AU', + 'Coral Sea Islands' => 'AU', + 'Clipperton Island' => 'FR', + 'Ashmore and Cartier Islands' => 'AU', + 'Norway' => 'NO' + }.freeze + def country_flag(country_name) country_code = country_to_code(country_name) return '' unless country_code country_code = 'TW' if country_code == 'CN-TW' - # Convert country code to regional indicator symbols (flag emoji) - country_code.upcase.each_char.map { |c| (c.ord + 127_397).chr(Encoding::UTF_8) }.join + # Resolve -99 territories via name lookup + if country_code == '-99' + country_code = TERRITORY_CODES[country_name] + return '' unless country_code + end + + # Skip any remaining non-alpha-2 codes + return '' unless country_code.match?(/\A[A-Za-z]{2}\z/) + + icon(country_code.downcase, library: 'flags', title: country_name) end private diff --git a/app/javascript/controllers/maps/maplibre_controller.js b/app/javascript/controllers/maps/maplibre_controller.js index 5cb5b3f1c..179ca6943 100644 --- a/app/javascript/controllers/maps/maplibre_controller.js +++ b/app/javascript/controllers/maps/maplibre_controller.js @@ -1242,7 +1242,7 @@ export default class extends Controller { // Find the point index closest to (or at) the target minute let targetIndex = 0 for (let i = 0; i < dayPoints.length; i++) { - const timestamp = this.timelineManager._getTimestamp(dayPoints[i]) + const timestamp = this.timelineManager.getTimestamp(dayPoints[i]) const pointTime = this._parseTimelineTimestamp(timestamp) if (pointTime) { const date = new Date(pointTime) @@ -1568,8 +1568,8 @@ export default class extends Controller { const currentDay = this.timelineManager.getCurrentDay() if (!currentDay) return - const dayPoints = this.timelineManager.pointsByDay[currentDay] - if (!dayPoints || dayPoints.length === 0) return + const dayPoints = this.timelineManager.getPointsForDay(currentDay) + if (dayPoints.length === 0) return this.timelineReplayActive = true this.timelineReplaySpeed = this.timelineReplaySpeed || 2 @@ -1579,7 +1579,7 @@ export default class extends Controller { // Find starting index based on current scrubber position const currentMinute = parseInt(this.timelineScrubberTarget.value, 10) for (let i = 0; i < dayPoints.length; i++) { - const timestamp = this.timelineManager._getTimestamp(dayPoints[i]) + const timestamp = this.timelineManager.getTimestamp(dayPoints[i]) const pointTime = this._parseTimelineTimestamp(timestamp) if (pointTime) { const date = new Date(pointTime) @@ -1736,7 +1736,7 @@ export default class extends Controller { // Get points for new day const newDay = this.timelineManager.getCurrentDay() this.timelineReplayPoints = - this.timelineManager.pointsByDay[newDay] || [] + this.timelineManager.getPointsForDay(newDay) this.timelineReplayPointIndex = 0 if (this.timelineReplayPoints.length === 0) { @@ -1772,7 +1772,7 @@ export default class extends Controller { this._updateTimelineSpeedDisplay(this._getPointVelocity(currentPoint)) // Get minute for this point to update scrubber - const timestamp = this.timelineManager._getTimestamp(currentPoint) + const timestamp = this.timelineManager.getTimestamp(currentPoint) const pointTime = this._parseTimelineTimestamp(timestamp) if (pointTime) { const date = new Date(pointTime) @@ -1873,7 +1873,7 @@ export default class extends Controller { const timelineMarkerLayer = this.layerManager?.getLayer("timelineMarker") if (timelineMarkerLayer) { timelineMarkerLayer.showMarker(coords.lon, coords.lat, { - timestamp: this.timelineManager._getTimestamp(point), + timestamp: this.timelineManager.getTimestamp(point), }) } } @@ -1924,7 +1924,7 @@ export default class extends Controller { return } - const timestamp = this.timelineManager._getTimestamp(point) + const timestamp = this.timelineManager.getTimestamp(point) if (!timestamp) { routesLayer.setHoverRoute(null) return diff --git a/app/javascript/controllers/trip_maplibre_controller.js b/app/javascript/controllers/trip_maplibre_controller.js new file mode 100644 index 000000000..8b91c9ba3 --- /dev/null +++ b/app/javascript/controllers/trip_maplibre_controller.js @@ -0,0 +1,1139 @@ +import { Controller } from "@hotwired/stimulus" +import { MapInitializer } from "controllers/maps/maplibre/map_initializer" +import maplibregl from "maplibre-gl" +import { DayRoutesLayer } from "maps_maplibre/layers/day_routes_layer" +import { PhotosLayer } from "maps_maplibre/layers/photos_layer" +import { TimelineMarkerLayer } from "maps_maplibre/layers/timeline_marker_layer" +import { TimelineManager } from "maps_maplibre/managers/timeline_manager" +import { ApiClient } from "maps_maplibre/services/api_client" + +/** + * Trip MapLibre Controller + * Renders a MapLibre map for the trip show page with day-colored routes, + * an accordion-based day navigator, photos overlay, and timeline replay. + */ +export default class extends Controller { + static targets = [ + "map", + "daysAccordion", + "expandAllBtn", + "loadingIndicator", + // Photos button + "photosToggleBtn", + // Timeline toggle button + "timelineToggleBtn", + // Timeline panel + "timelinePanel", + "timelineScrubber", + "timelineScrubberTrack", + "timelineDensityContainer", + "timelineDayDisplay", + "timelineDayCount", + "timelineTimeDisplay", + "timelineDataIndicator", + "timelineCycleControls", + "timelinePointCounter", + "timelinePrevDayButton", + "timelineNextDayButton", + "timelinePlayButton", + "timelinePlayIcon", + "timelinePauseIcon", + "timelineSpeedSlider", + "timelineSpeedLabel", + "timelineSpeedDisplay", + ] + + static values = { + apiKey: String, + timezone: String, + startedAt: String, + endedAt: String, + tripId: Number, + pathData: String, + mapStyle: { type: String, default: "light" }, + } + + async connect() { + this.pointsByDay = {} + this.selectedDay = null + this.dayRoutesLayer = null + this.photosLayer = null + this.photosGeoJSON = null + this.photosActive = false + this.mapInitializing = false + this.overviewSourceId = "trip-overview-source" + this.overviewLayerId = "trip-overview-layer" + + // Timeline state + this.timelineManager = null + this.timelineMarkerLayer = null + this.timelineReplayActive = false + this.timelineReplaySpeed = 2 + this.timelineReplayPoints = [] + this.timelineReplayPointIndex = 0 + this.timelineReplayLastTime = 0 + this.timelineReplayAnimationId = null + this.timelineReplayCurrentCoords = null + this.timelineReplayNextCoords = null + + if (this.hasMapTarget) { + await this.initializeMap() + } + } + + disconnect() { + this._stopTimelineReplay() + if (this.timelineMarkerLayer) { + this.timelineMarkerLayer.clear() + } + if (this.photosLayer) { + this.photosLayer.remove() + this.photosLayer = null + } + if (this.dayRoutesLayer) { + this.dayRoutesLayer.remove() + } + if (this.map) { + this.map.remove() + this.map = null + } + this.mapInitializing = false + } + + async mapTargetConnected() { + if (!this.map && !this.mapInitializing) { + await this.initializeMap() + } + } + + async initializeMap() { + if (!this.hasMapTarget || this.mapInitializing) return + this.mapInitializing = true + + this.map = await MapInitializer.initialize(this.mapTarget, { + mapStyle: this.mapStyleValue, + center: [0, 0], + zoom: 2, + showControls: true, + }) + + this.map.on("load", async () => { + this.showPathOverview() + await this.fetchAndProcessPoints() + }) + } + + getPathData() { + const raw = + this.pathDataValue || + (this.hasMapTarget && this.mapTarget.dataset.pathCoordinates) + return raw || null + } + + showPathOverview() { + const pathData = this.getPathData() + if (!pathData) return + + try { + const coordinates = JSON.parse(pathData) + if (!coordinates.length) return + + if (this.map.getSource(this.overviewSourceId)) return + + const geojson = { + type: "Feature", + geometry: { + type: "LineString", + coordinates: coordinates, + }, + } + + this.map.addSource(this.overviewSourceId, { + type: "geojson", + data: geojson, + }) + + this.map.addLayer({ + id: this.overviewLayerId, + type: "line", + source: this.overviewSourceId, + layout: { + "line-join": "round", + "line-cap": "round", + }, + paint: { + "line-color": "#6366F1", + "line-width": 3, + "line-opacity": 0.8, + }, + }) + + const bounds = new maplibregl.LngLatBounds() + for (const coord of coordinates) { + bounds.extend(coord) + } + if (!bounds.isEmpty()) { + this.map.fitBounds(bounds, { padding: 50, maxZoom: 15 }) + } + } catch (e) { + console.error("[TripMapLibre] Error showing path overview:", e) + } + } + + async fetchAndProcessPoints() { + const apiClient = new ApiClient(this.apiKeyValue) + + try { + this.showLoading(true) + + const allPoints = await apiClient.fetchAllPoints({ + start_at: this.startedAtValue, + end_at: this.endedAtValue, + }) + + if (!allPoints.length) { + this.showLoading(false) + return + } + + // Use TimelineManager for canonical day grouping + const grouper = new TimelineManager({ timezone: this.timezoneValue }) + grouper.setPoints(allPoints) + this.pointsByDay = {} + for (const dayKey of grouper.availableDays) { + this.pointsByDay[dayKey] = grouper.getPointsForDay(dayKey) + } + const dayKeys = Object.keys(this.pointsByDay).sort() + + if (!dayKeys.length) { + this.showLoading(false) + return + } + + this.removeOverviewLine() + + this.dayRoutesLayer = new DayRoutesLayer(this.map) + this.dayRoutesLayer.addDayRoutes(this.pointsByDay) + + this.applyDayColors(dayKeys) + + this.dayRoutesLayer.setupInteractions({ + onDayClick: (dayKey) => this.selectDayFromMap(dayKey), + }) + + const fullBounds = this.dayRoutesLayer.getFullBounds() + if (fullBounds) { + this.map.fitBounds(fullBounds, { padding: 50, maxZoom: 15 }) + } + + // Store all points for timeline use + this.allPoints = allPoints + + this.showLoading(false) + } catch (e) { + console.error("[TripMapLibre] Error fetching points:", e) + this.showLoading(false) + } + } + + applyDayColors(dayKeys) { + if (!this.hasDaysAccordionTarget) return + + for (const dayKey of dayKeys) { + const color = this.dayRoutesLayer.getDayColor(dayKey) + const dot = this.daysAccordionTarget.querySelector( + `[data-day-dot="${dayKey}"]`, + ) + if (dot && color) { + dot.style.backgroundColor = color + } + } + } + + selectDayFromMap(dayKey) { + if (!this.hasDaysAccordionTarget) return + + const allDetails = this.daysAccordionTarget.querySelectorAll( + "details[data-day-key]", + ) + const target = this.daysAccordionTarget.querySelector( + `details[data-day-key="${dayKey}"]`, + ) + if (!target) return + + for (const d of allDetails) { + if (d !== target) { + d.removeAttribute("open") + } + } + target.setAttribute("open", "") + + this.selectedDay = dayKey + + if (this.dayRoutesLayer) { + this.dayRoutesLayer.selectDay(dayKey) + + const dayBounds = this.dayRoutesLayer.getDayBounds(dayKey) + if (dayBounds) { + this.map.fitBounds(dayBounds, { padding: 50, maxZoom: 15 }) + } + } + + target.scrollIntoView({ behavior: "smooth", block: "nearest" }) + + this._syncTimelineToDay(dayKey) + } + + toggleDay(event) { + event.preventDefault() + + const summary = event.currentTarget + const details = summary.closest("details") + const dayKey = summary.dataset.tripMaplibreDayKeyParam + if (!details || !dayKey) return + + if (details.open) { + details.removeAttribute("open") + this.selectedDay = null + + if (this.dayRoutesLayer) { + this.dayRoutesLayer.selectAllDays() + + const fullBounds = this.dayRoutesLayer.getFullBounds() + if (fullBounds) { + this.map.fitBounds(fullBounds, { padding: 50, maxZoom: 15 }) + } + } + } else { + const allDetails = this.daysAccordionTarget.querySelectorAll( + "details[data-day-key]", + ) + for (const d of allDetails) { + if (d !== details) { + d.removeAttribute("open") + } + } + details.setAttribute("open", "") + + this.selectedDay = dayKey + + if (this.dayRoutesLayer) { + this.dayRoutesLayer.selectDay(dayKey) + + const dayBounds = this.dayRoutesLayer.getDayBounds(dayKey) + if (dayBounds) { + this.map.fitBounds(dayBounds, { padding: 50, maxZoom: 15 }) + } + } + + this._syncTimelineToDay(dayKey) + } + } + + expandAllDays() { + if (!this.hasDaysAccordionTarget) return + + const allDetails = this.daysAccordionTarget.querySelectorAll( + "details[data-day-key]", + ) + const allOpen = Array.from(allDetails).every((d) => d.hasAttribute("open")) + + if (allOpen) { + for (const d of allDetails) { + d.removeAttribute("open") + } + if (this.hasExpandAllBtnTarget) { + this.expandAllBtnTarget.textContent = "Show all days" + } + } else { + for (const d of allDetails) { + d.setAttribute("open", "") + } + if (this.hasExpandAllBtnTarget) { + this.expandAllBtnTarget.textContent = "Collapse all days" + } + } + + this.selectedDay = null + + if (this.dayRoutesLayer) { + this.dayRoutesLayer.selectAllDays() + + const fullBounds = this.dayRoutesLayer.getFullBounds() + if (fullBounds) { + this.map.fitBounds(fullBounds, { padding: 50, maxZoom: 15 }) + } + } + } + + removeOverviewLine() { + if (this.map.getLayer(this.overviewLayerId)) { + this.map.removeLayer(this.overviewLayerId) + } + if (this.map.getSource(this.overviewSourceId)) { + this.map.removeSource(this.overviewSourceId) + } + } + + showLoading(show) { + if (this.hasLoadingIndicatorTarget) { + this.loadingIndicatorTarget.classList.toggle("hidden", !show) + } + } + + // ===== Photos layer toggle (button-based) ===== + + async togglePhotos() { + this.photosActive = !this.photosActive + + if (!this.photosActive) { + if (this.photosLayer) { + this.photosLayer.remove() + this.photosLayer = null + } + this._setButtonActive(this.photosToggleBtnTarget, false) + return + } + + if (!this.photosGeoJSON) { + const apiClient = new ApiClient(this.apiKeyValue) + try { + const photos = await apiClient.fetchPhotos({ + start_at: this.startedAtValue, + end_at: this.endedAtValue, + }) + this.photosGeoJSON = this.photosToGeoJSON(photos) + } catch (e) { + console.error("[TripMapLibre] Error fetching photos:", e) + this.photosActive = false + return + } + } + + if (this.photosGeoJSON.features.length === 0) { + this.photosActive = false + return + } + + this.photosLayer = new PhotosLayer(this.map) + this.photosLayer.add(this.photosGeoJSON) + this._setButtonActive(this.photosToggleBtnTarget, true) + } + + photosToGeoJSON(photos) { + return { + type: "FeatureCollection", + features: photos.map((photo) => { + const thumbnailUrl = `/api/v1/photos/${photo.id}/thumbnail.jpg?api_key=${this.apiKeyValue}&source=${photo.source}` + return { + type: "Feature", + geometry: { + type: "Point", + coordinates: [photo.longitude, photo.latitude], + }, + properties: { + id: photo.id, + thumbnail_url: thumbnailUrl, + taken_at: photo.localDateTime, + filename: photo.originalFileName, + city: photo.city, + state: photo.state, + country: photo.country, + type: photo.type, + source: photo.source, + }, + } + }), + } + } + + // ===== Note form toggling ===== + + showNoteForm(event) { + this.toggleNoteVisibility(event.currentTarget.dataset.date, true) + } + + hideNoteForm(event) { + this.toggleNoteVisibility(event.currentTarget.dataset.date, false) + } + + toggleNoteVisibility(date, showForm) { + const display = this.element.querySelector(`[data-note-display="${date}"]`) + const form = this.element.querySelector(`[data-note-form="${date}"]`) + if (display) display.classList.toggle("hidden", showForm) + if (form) form.classList.toggle("hidden", !showForm) + } + + // ===== Timeline ===== + + toggleTimeline() { + if (!this.hasTimelinePanelTarget) return + + const isVisible = !this.timelinePanelTarget.classList.contains("hidden") + + if (isVisible) { + this._stopTimelineReplay() + this.timelinePanelTarget.classList.add("hidden") + this._clearTimelineMarker() + this._updateTimelineSpeedDisplay(null) + this._setButtonActive(this.timelineToggleBtnTarget, false) + } else { + this._initializeTimeline() + this.timelinePanelTarget.classList.remove("hidden") + this._setButtonActive(this.timelineToggleBtnTarget, true) + } + } + + _initializeTimeline() { + if (!this.allPoints || this.allPoints.length === 0) return + + this.timelineManager = new TimelineManager({ + timezone: this.timezoneValue, + }) + + this.timelineManager.setPoints(this.allPoints) + + if (!this.timelineManager.hasData()) return + + // Initialize timeline marker layer if needed + if (!this.timelineMarkerLayer) { + this.timelineMarkerLayer = new TimelineMarkerLayer(this.map) + this.timelineMarkerLayer.add() + } + + this._updateTimelineDayDisplay() + this._updateTimelineDayCount() + this._updateTimelineDayButtons() + this._renderTimelineDensity() + this._initializeTimelineReplay() + this._setInitialScrubberPosition() + this._hideTimelineCycleControls() + } + + _setInitialScrubberPosition() { + if (!this.hasTimelineScrubberTarget || !this.timelineManager) return + + const firstMinute = this.timelineManager.findNearestMinuteWithPoints(0) + if (firstMinute !== null) { + this.timelineScrubberTarget.value = firstMinute + this._handleTimelineMinuteChange(firstMinute) + } else { + this.timelineScrubberTarget.value = 720 + this._updateTimelineTimeDisplay(720, true) + } + } + + timelineScrubberHover(event) { + const minute = parseInt(event.target.value, 10) + this._handleTimelineMinuteChange(minute) + } + + _handleTimelineMinuteChange(minute) { + if (!this.timelineManager) return + + const hasDataAtMinute = this.timelineManager.hasDataAtMinute(minute) + const nearestMinute = + this.timelineManager.findNearestMinuteWithPoints(minute) + + this._updateTimelineTimeDisplay(minute, !hasDataAtMinute) + + if (nearestMinute === null) { + this._clearTimelineMarker() + this._hideTimelineCycleControls() + this._updateTimelineSpeedDisplay(null) + return + } + + if (!hasDataAtMinute || nearestMinute !== minute) { + this.timelineManager.resetCycle() + } + + const point = this.timelineManager.getPointAtPosition(nearestMinute) + if (!point) return + + this._showTimelineMarker(point) + this._updateTimelineSpeedDisplay(this._getPointVelocity(point)) + this._flyToTimelinePoint(point, this.timelineReplayActive) + + if (hasDataAtMinute) { + this._updateTimelineCycleControls(minute) + } else { + this._hideTimelineCycleControls() + } + + // Sync timeline day with accordion + this._syncAccordionWithTimelineDay() + + if (this.timelineReplayActive && this.timelineReplayPoints?.length > 0) { + this._jumpReplayToMinute(minute) + } + } + + _jumpReplayToMinute(minute) { + const dayPoints = this.timelineReplayPoints + if (!dayPoints || dayPoints.length === 0) return + + let targetIndex = 0 + for (let i = 0; i < dayPoints.length; i++) { + const timestamp = this.timelineManager.getTimestamp(dayPoints[i]) + const pointTime = this._parseTimelineTimestamp(timestamp) + if (pointTime) { + const date = new Date(pointTime) + const pointMinute = date.getHours() * 60 + date.getMinutes() + if (pointMinute >= minute) { + targetIndex = i + break + } + targetIndex = i + } + } + + this.timelineReplayPointIndex = targetIndex + + const currentPoint = dayPoints[targetIndex] + const nextPoint = dayPoints[targetIndex + 1] + + this.timelineReplayCurrentCoords = currentPoint + ? this.timelineManager.getCoordinates(currentPoint) + : null + this.timelineReplayNextCoords = nextPoint + ? this.timelineManager.getCoordinates(nextPoint) + : this.timelineReplayCurrentCoords + + this.timelineReplayLastTime = performance.now() + } + + // --- Day navigation --- + + timelinePrevDay() { + if (!this.timelineManager) return + + this._stopTimelineReplay() + + if (this.timelineManager.prevDay()) { + this._updateTimelineDayDisplay() + this._updateTimelineDayCount() + this._updateTimelineDayButtons() + this._renderTimelineDensity() + this._setInitialScrubberPosition() + this._clearTimelineMarker() + this._hideTimelineCycleControls() + this._syncAccordionWithTimelineDay() + } + } + + timelineNextDay() { + if (!this.timelineManager) return + + this._stopTimelineReplay() + + if (this.timelineManager.nextDay()) { + this._updateTimelineDayDisplay() + this._updateTimelineDayCount() + this._updateTimelineDayButtons() + this._renderTimelineDensity() + this._setInitialScrubberPosition() + this._clearTimelineMarker() + this._hideTimelineCycleControls() + this._syncAccordionWithTimelineDay() + } + } + + // --- Point cycling --- + + timelineCyclePrev() { + if (!this.timelineManager || !this.hasTimelineScrubberTarget) return + + const minute = parseInt(this.timelineScrubberTarget.value, 10) + this.timelineManager.cyclePrev() + + const point = this.timelineManager.getPointAtPosition(minute) + if (point) { + this._showTimelineMarker(point) + this._updateTimelineSpeedDisplay(this._getPointVelocity(point)) + this._flyToTimelinePoint(point) + this._updateTimelineCycleControls(minute) + } + } + + timelineCycleNext() { + if (!this.timelineManager || !this.hasTimelineScrubberTarget) return + + const minute = parseInt(this.timelineScrubberTarget.value, 10) + this.timelineManager.cycleNext(minute) + + const point = this.timelineManager.getPointAtPosition(minute) + if (point) { + this._showTimelineMarker(point) + this._updateTimelineSpeedDisplay(this._getPointVelocity(point)) + this._flyToTimelinePoint(point) + this._updateTimelineCycleControls(minute) + } + } + + // --- UI updates --- + + _updateTimelineDayDisplay() { + if (!this.hasTimelineDayDisplayTarget || !this.timelineManager) return + this.timelineDayDisplayTarget.textContent = + this.timelineManager.getCurrentDayDisplay() + } + + _updateTimelineDayButtons() { + if (!this.timelineManager) return + + if (this.hasTimelinePrevDayButtonTarget) { + this.timelinePrevDayButtonTarget.disabled = + !this.timelineManager.canGoPrev() + } + + if (this.hasTimelineNextDayButtonTarget) { + this.timelineNextDayButtonTarget.disabled = + !this.timelineManager.canGoNext() + } + } + + _updateTimelineTimeDisplay(minute, showNoData = false) { + if (this.hasTimelineTimeDisplayTarget) { + this.timelineTimeDisplayTarget.textContent = + TimelineManager.formatMinuteToTime(minute) + } + + if (this.hasTimelineDataIndicatorTarget) { + if (showNoData) { + this.timelineDataIndicatorTarget.classList.remove("hidden") + this.timelineDataIndicatorTarget.textContent = "No data at this time" + } else { + this.timelineDataIndicatorTarget.classList.add("hidden") + } + } + } + + _getPointVelocity(point) { + if (!point) return null + if (point.properties?.velocity !== undefined) { + return point.properties.velocity + } + if (point.velocity !== undefined) { + return point.velocity + } + return null + } + + _updateTimelineSpeedDisplay(velocity) { + if (!this.hasTimelineSpeedDisplayTarget) return + + if (velocity !== null && velocity !== undefined && velocity !== "") { + const speedMs = parseFloat(velocity) + if (!Number.isNaN(speedMs) && speedMs > 0) { + const speedKmh = speedMs * 3.6 + this.timelineSpeedDisplayTarget.textContent = `${Math.round(speedKmh)} km/h` + } else { + this.timelineSpeedDisplayTarget.textContent = "" + } + } else { + this.timelineSpeedDisplayTarget.textContent = "" + } + } + + _updateTimelineDayCount() { + if (!this.hasTimelineDayCountTarget || !this.timelineManager) return + + const dayCount = this.timelineManager.getDayCount() + const currentIndex = this.timelineManager.currentDayIndex + 1 + const pointCount = this.timelineManager.getCurrentDayPointCount() + + this.timelineDayCountTarget.textContent = `Day ${currentIndex} of ${dayCount} \u2022 ${pointCount.toLocaleString()} points` + } + + _renderTimelineDensity() { + if (!this.hasTimelineDensityContainerTarget || !this.timelineManager) return + + const segments = 48 + const density = this.timelineManager.getDataDensity(segments) + + while (this.timelineDensityContainerTarget.firstChild) { + this.timelineDensityContainerTarget.removeChild( + this.timelineDensityContainerTarget.firstChild, + ) + } + + density.forEach((value) => { + const bar = document.createElement("div") + bar.className = "timeline-density-bar" + + if (value > 0) { + bar.classList.add("has-data") + if (value > 0.5) { + bar.classList.add("high-density") + } + } + + this.timelineDensityContainerTarget.appendChild(bar) + }) + } + + _updateTimelineCycleControls(minute) { + if (!this.hasTimelineCycleControlsTarget || !this.timelineManager) return + + const count = this.timelineManager.getPointCountAtMinute(minute) + + if (count > 1) { + this.timelineCycleControlsTarget.classList.remove("hidden") + if (this.hasTimelinePointCounterTarget) { + const currentIndex = (this.timelineManager.cycleIndex % count) + 1 + this.timelinePointCounterTarget.textContent = `Point ${currentIndex} of ${count}` + } + } else { + this.timelineCycleControlsTarget.classList.add("hidden") + } + } + + _hideTimelineCycleControls() { + if (this.hasTimelineCycleControlsTarget) { + this.timelineCycleControlsTarget.classList.add("hidden") + } + } + + // ===== Timeline Replay ===== + + timelineToggleReplay() { + if (this.timelineReplayActive) { + this._stopTimelineReplay() + } else { + this._startTimelineReplay() + } + } + + timelineSpeedChange(event) { + const speedIndex = parseInt(event.target.value, 10) + const speeds = [1, 2, 5, 10] + this.timelineReplaySpeed = speeds[speedIndex - 1] || 2 + + if (this.hasTimelineSpeedLabelTarget) { + this.timelineSpeedLabelTarget.textContent = `${this.timelineReplaySpeed}x` + } + } + + _startTimelineReplay() { + if (this.timelineReplayActive) return + if (!this.timelineManager || !this.hasTimelineScrubberTarget) return + + const currentDay = this.timelineManager.getCurrentDay() + if (!currentDay) return + + const dayPoints = this.timelineManager.getPointsForDay(currentDay) + if (dayPoints.length === 0) return + + this.timelineReplayActive = true + this.timelineReplaySpeed = this.timelineReplaySpeed || 2 + this.timelineReplayPoints = dayPoints + this.timelineReplayPointIndex = 0 + + const currentMinute = parseInt(this.timelineScrubberTarget.value, 10) + for (let i = 0; i < dayPoints.length; i++) { + const timestamp = this.timelineManager.getTimestamp(dayPoints[i]) + const pointTime = this._parseTimelineTimestamp(timestamp) + if (pointTime) { + const date = new Date(pointTime) + const pointMinute = date.getHours() * 60 + date.getMinutes() + if (pointMinute >= currentMinute) { + this.timelineReplayPointIndex = i + break + } + } + } + + const startPoint = dayPoints[this.timelineReplayPointIndex] + const nextPoint = dayPoints[this.timelineReplayPointIndex + 1] + this.timelineReplayCurrentCoords = startPoint + ? this.timelineManager.getCoordinates(startPoint) + : null + this.timelineReplayNextCoords = nextPoint + ? this.timelineManager.getCoordinates(nextPoint) + : this.timelineReplayCurrentCoords + + if (startPoint) { + this._showTimelineMarker(startPoint) + this._flyToTimelinePoint(startPoint, true) + } + + if (this.hasTimelinePlayButtonTarget) { + this.timelinePlayButtonTarget.classList.add("playing") + } + if (this.hasTimelinePlayIconTarget) { + this.timelinePlayIconTarget.classList.add("hidden") + } + if (this.hasTimelinePauseIconTarget) { + this.timelinePauseIconTarget.classList.remove("hidden") + } + + this.timelineReplayLastTime = performance.now() + this._timelineReplayFrame() + } + + _stopTimelineReplay() { + if (this.timelineReplayActive === undefined) return + + this.timelineReplayActive = false + + if (this.timelineReplayAnimationId) { + cancelAnimationFrame(this.timelineReplayAnimationId) + this.timelineReplayAnimationId = null + } + + if (this.hasTimelinePlayButtonTarget) { + this.timelinePlayButtonTarget.classList.remove("playing") + } + if (this.hasTimelinePlayIconTarget) { + this.timelinePlayIconTarget.classList.remove("hidden") + } + if (this.hasTimelinePauseIconTarget) { + this.timelinePauseIconTarget.classList.add("hidden") + } + } + + _initializeTimelineReplay() { + this.timelineReplayActive = false + this.timelineReplaySpeed = 2 + this.timelineReplayPoints = [] + this.timelineReplayPointIndex = 0 + this.timelineReplayLastTime = 0 + this.timelineReplayAnimationId = null + this.timelineReplayCurrentCoords = null + this.timelineReplayNextCoords = null + + if (this.hasTimelineSpeedLabelTarget) { + this.timelineSpeedLabelTarget.textContent = "2x" + } + if (this.hasTimelineSpeedSliderTarget) { + this.timelineSpeedSliderTarget.value = 2 + } + } + + _timelineReplayFrame() { + if (!this.timelineReplayActive) return + + const now = performance.now() + const elapsed = now - this.timelineReplayLastTime + const intervalMs = 500 / this.timelineReplaySpeed + const progress = Math.min(elapsed / intervalMs, 1) + + if (this.timelineReplayCurrentCoords && this.timelineReplayNextCoords) { + const currentLon = + this.timelineReplayCurrentCoords.lon + + (this.timelineReplayNextCoords.lon - + this.timelineReplayCurrentCoords.lon) * + progress + const currentLat = + this.timelineReplayCurrentCoords.lat + + (this.timelineReplayNextCoords.lat - + this.timelineReplayCurrentCoords.lat) * + progress + + this._showTimelineMarkerAt(currentLon, currentLat) + this._panMapToFollowMarker(currentLon, currentLat) + } + + if (elapsed >= intervalMs) { + this.timelineReplayLastTime = now + this.timelineReplayPointIndex++ + + if (this.timelineReplayPointIndex >= this.timelineReplayPoints.length) { + if (this.timelineManager.canGoNext()) { + this.timelineManager.nextDay() + this._updateTimelineDayDisplay() + this._updateTimelineDayCount() + this._updateTimelineDayButtons() + this._renderTimelineDensity() + this._syncAccordionWithTimelineDay() + + const newDay = this.timelineManager.getCurrentDay() + this.timelineReplayPoints = + this.timelineManager.getPointsForDay(newDay) + this.timelineReplayPointIndex = 0 + + if (this.timelineReplayPoints.length === 0) { + this._stopTimelineReplay() + return + } + } else { + this._stopTimelineReplay() + return + } + } + + const currentPoint = + this.timelineReplayPoints[this.timelineReplayPointIndex] + const nextPoint = + this.timelineReplayPoints[this.timelineReplayPointIndex + 1] + + if (!currentPoint) { + this._stopTimelineReplay() + return + } + + this.timelineReplayCurrentCoords = + this.timelineManager.getCoordinates(currentPoint) + this.timelineReplayNextCoords = nextPoint + ? this.timelineManager.getCoordinates(nextPoint) + : this.timelineReplayCurrentCoords + + this._updateTimelineSpeedDisplay(this._getPointVelocity(currentPoint)) + + const timestamp = this.timelineManager.getTimestamp(currentPoint) + const pointTime = this._parseTimelineTimestamp(timestamp) + if (pointTime) { + const date = new Date(pointTime) + const minute = date.getHours() * 60 + date.getMinutes() + + this.timelineScrubberTarget.value = minute + this._updateTimelineTimeDisplay(minute, false) + } + + this._hideTimelineCycleControls() + } + + this.timelineReplayAnimationId = requestAnimationFrame(() => + this._timelineReplayFrame(), + ) + } + + _panMapToFollowMarker(lon, lat) { + if (!this.map) return + + const bounds = this.map.getBounds() + const center = this.map.getCenter() + + const lngSpan = bounds.getEast() - bounds.getWest() + const latSpan = bounds.getNorth() - bounds.getSouth() + + const lngOffset = (lon - center.lng) / lngSpan + const latOffset = (lat - center.lat) / latSpan + + const threshold = 0.3 + if (Math.abs(lngOffset) > threshold || Math.abs(latOffset) > threshold) { + this.map.setCenter([lon, lat]) + } + } + + // --- Marker helpers --- + + _showTimelineMarker(point) { + const coords = this.timelineManager?.getCoordinates(point) + if (!coords) return + + if (this.timelineMarkerLayer) { + this.timelineMarkerLayer.showMarker(coords.lon, coords.lat, { + timestamp: this.timelineManager.getTimestamp(point), + }) + } + } + + _showTimelineMarkerAt(lon, lat) { + if (lon === undefined || lat === undefined) return + + if (this.timelineMarkerLayer) { + this.timelineMarkerLayer.showMarker(lon, lat) + } + } + + _clearTimelineMarker() { + if (this.timelineMarkerLayer) { + this.timelineMarkerLayer.clear() + } + } + + _flyToTimelinePoint(point, fast = false) { + const coords = this.timelineManager?.getCoordinates(point) + if (!coords || !this.map) return + + this.map.flyTo({ + center: [coords.lon, coords.lat], + zoom: Math.max(this.map.getZoom(), 14), + duration: fast ? 100 : 500, + }) + } + + _parseTimelineTimestamp(timestamp) { + if (!timestamp) return 0 + + if (typeof timestamp === "string") { + return new Date(timestamp).getTime() + } + + if (typeof timestamp === "number") { + if (timestamp < 10000000000) { + return timestamp * 1000 + } + return timestamp + } + + return 0 + } + + // --- Timeline <-> day sync --- + + _syncTimelineToDay(dayKey) { + if (!this.timelineManager) return + if (!this.hasTimelinePanelTarget) return + if (this.timelinePanelTarget.classList.contains("hidden")) return + + this._stopTimelineReplay() + + if (this.timelineManager.goToDay(dayKey)) { + this._updateTimelineDayDisplay() + this._updateTimelineDayCount() + this._updateTimelineDayButtons() + this._renderTimelineDensity() + this._setInitialScrubberPosition() + this._clearTimelineMarker() + this._hideTimelineCycleControls() + } + } + + // --- Accordion sync --- + + _syncAccordionWithTimelineDay() { + if (!this.hasDaysAccordionTarget || !this.timelineManager) return + + const currentDay = this.timelineManager.getCurrentDay() + if (!currentDay) return + + const allDetails = this.daysAccordionTarget.querySelectorAll( + "details[data-day-key]", + ) + const target = this.daysAccordionTarget.querySelector( + `details[data-day-key="${currentDay}"]`, + ) + + for (const d of allDetails) { + if (d !== target) { + d.removeAttribute("open") + } + } + + if (target) { + target.setAttribute("open", "") + target.scrollIntoView({ behavior: "smooth", block: "nearest" }) + } + + // Also highlight the day route on the map + if (this.dayRoutesLayer) { + this.dayRoutesLayer.selectDay(currentDay) + } + } + + // --- Button active state helper --- + + _setButtonActive(button, active) { + if (!button) return + if (active) { + button.classList.remove("btn-outline") + button.classList.add("btn-active", "btn-primary") + } else { + button.classList.remove("btn-active", "btn-primary") + button.classList.add("btn-outline") + } + } +} diff --git a/app/javascript/controllers/trip_maplibre_preview_controller.js b/app/javascript/controllers/trip_maplibre_preview_controller.js new file mode 100644 index 000000000..89fb2cd47 --- /dev/null +++ b/app/javascript/controllers/trip_maplibre_preview_controller.js @@ -0,0 +1,90 @@ +import { Controller } from "@hotwired/stimulus" +import { MapInitializer } from "controllers/maps/maplibre/map_initializer" +import maplibregl from "maplibre-gl" + +/** + * Lightweight MapLibre controller for trip card previews on the index page. + * Renders a static, non-interactive map with the trip path as a single line. + */ +export default class extends Controller { + static values = { + path: String, + mapStyle: { type: String, default: "light" }, + } + + async connect() { + this.map = await MapInitializer.initialize(this.element, { + mapStyle: this.mapStyleValue, + center: [0, 0], + zoom: 2, + showControls: false, + }) + + // Disable all interaction for a static preview + this.map.dragPan.disable() + this.map.scrollZoom.disable() + this.map.boxZoom.disable() + this.map.dragRotate.disable() + this.map.doubleClickZoom.disable() + this.map.touchZoomRotate.disable() + this.map.keyboard.disable() + + this.map.on("load", () => { + this.showRoute() + }) + } + + showRoute() { + if (!this.hasPathValue || !this.pathValue) return + + let coordinates + try { + coordinates = JSON.parse(this.pathValue) + } catch (_e) { + return + } + + if (!coordinates.length) return + + this.map.addSource("trip-path", { + type: "geojson", + data: { + type: "Feature", + geometry: { + type: "LineString", + coordinates, + }, + }, + }) + + this.map.addLayer({ + id: "trip-path-layer", + type: "line", + source: "trip-path", + layout: { + "line-join": "round", + "line-cap": "round", + }, + paint: { + "line-color": "#6366F1", + "line-width": 3, + "line-opacity": 0.9, + }, + }) + + const bounds = new maplibregl.LngLatBounds() + for (const coord of coordinates) { + bounds.extend(coord) + } + if (!bounds.isEmpty()) { + this.map.fitBounds(bounds, { padding: 20, maxZoom: 15, animate: false }) + } + } + + disconnect() { + if (this.map) { + this.map.remove() + this.map = null + } + } +} diff --git a/app/javascript/maps_maplibre/layers/day_routes_layer.js b/app/javascript/maps_maplibre/layers/day_routes_layer.js new file mode 100644 index 000000000..c8656c755 --- /dev/null +++ b/app/javascript/maps_maplibre/layers/day_routes_layer.js @@ -0,0 +1,356 @@ +import maplibregl from "maplibre-gl" +import { RouteSegmenter } from "../utils/route_segmenter" + +/** + * DayRoutesLayer - Manages day-colored route layers for trips + * Each day gets its own source/layer with a distinct HSL color. + * Supports highlight/dim for day selection. + */ +export class DayRoutesLayer { + constructor(map) { + this.map = map + this.daySources = new Map() // dayKey -> sourceId + this.dayLayers = new Map() // dayKey -> layerId + this.dayColors = new Map() // dayKey -> color string + this.dayBounds = new Map() // dayKey -> LngLatBounds + this.fullBounds = null + this.selectedDay = null + } + + /** + * Generate N distinct colors using HSL rotation + * @param {number} numDays - Number of days + * @returns {string[]} Array of HSL color strings + */ + static generateDayPalette(numDays) { + // Curated palette: perceptually distinct, high contrast on map tiles + const PALETTE = [ + "#6366F1", // Indigo + "#F43F5E", // Rose + "#10B981", // Emerald + "#F59E0B", // Amber + "#0EA5E9", // Sky + "#A855F7", // Purple + "#F97316", // Orange + "#14B8A6", // Teal + "#EC4899", // Pink + "#84CC16", // Lime + "#06B6D4", // Cyan + "#D946EF", // Fuchsia + ] + + if (numDays === 1) return [PALETTE[0]] + if (numDays <= PALETTE.length) return PALETTE.slice(0, numDays) + + // Fall back to HSL rotation for trips > 12 days + return Array.from({ length: numDays }, (_, i) => { + const hue = (i * (360 / numDays)) % 360 + return `hsl(${hue}, 70%, 55%)` + }) + } + + /** + * Build and add day-colored routes to the map + * @param {Object} pointsByDay - { 'YYYY-MM-DD': [points...] } + * @param {Object} options - Route segmenter options + */ + addDayRoutes(pointsByDay, options = {}) { + const dayKeys = Object.keys(pointsByDay).sort() + const colors = DayRoutesLayer.generateDayPalette(dayKeys.length) + const allCoords = [] + + dayKeys.forEach((dayKey, i) => { + const points = pointsByDay[dayKey] + if (points.length < 2) return + + const color = colors[i] + this.dayColors.set(dayKey, color) + + // Use RouteSegmenter to build route GeoJSON for this day + const routeGeoJSON = RouteSegmenter.pointsToRoutes(points, { + distanceThresholdMeters: options.distanceThresholdMeters || 500, + timeThresholdMinutes: options.timeThresholdMinutes || 60, + }) + + // Set color on each feature + for (const feature of routeGeoJSON.features) { + feature.properties.color = color + feature.properties.dayKey = dayKey + } + + const sourceId = `day-route-${dayKey}` + const layerId = `day-route-layer-${dayKey}` + + this.daySources.set(dayKey, sourceId) + this.dayLayers.set(dayKey, layerId) + + // Add source + if (!this.map.getSource(sourceId)) { + this.map.addSource(sourceId, { + type: "geojson", + data: routeGeoJSON, + }) + } + + // Add layer + if (!this.map.getLayer(layerId)) { + this.map.addLayer({ + id: layerId, + type: "line", + source: sourceId, + layout: { + "line-join": "round", + "line-cap": "round", + }, + paint: { + "line-color": color, + "line-width": 3, + "line-opacity": 0.9, + }, + }) + } + + // Calculate bounds for this day + const dayBounds = new maplibregl.LngLatBounds() + for (const feature of routeGeoJSON.features) { + for (const coord of feature.geometry.coordinates) { + dayBounds.extend(coord) + } + } + if (!dayBounds.isEmpty()) { + this.dayBounds.set(dayKey, dayBounds) + } + + // Collect all coords for full bounds + for (const feature of routeGeoJSON.features) { + for (const coord of feature.geometry.coordinates) { + allCoords.push(coord) + } + } + }) + + // Calculate full trip bounds + if (allCoords.length > 0) { + this.fullBounds = new maplibregl.LngLatBounds() + for (const coord of allCoords) { + this.fullBounds.extend(coord) + } + } + } + + /** + * Highlight a specific day's route and dim others + * @param {string} dayKey - Day key like '2025-01-15' + */ + selectDay(dayKey) { + this.selectedDay = dayKey + + for (const [key, layerId] of this.dayLayers) { + if (!this.map.getLayer(layerId)) continue + + if (key === dayKey) { + this.map.setPaintProperty(layerId, "line-opacity", 1.0) + this.map.setPaintProperty(layerId, "line-width", 4) + } else { + this.map.setPaintProperty(layerId, "line-opacity", 0.25) + this.map.setPaintProperty(layerId, "line-width", 2) + } + } + } + + /** + * Show all days at normal opacity + */ + selectAllDays() { + this.selectedDay = null + + for (const [, layerId] of this.dayLayers) { + if (!this.map.getLayer(layerId)) continue + this.map.setPaintProperty(layerId, "line-opacity", 0.9) + this.map.setPaintProperty(layerId, "line-width", 3) + } + } + + /** + * Get bounds for a specific day + * @param {string} dayKey + * @returns {maplibregl.LngLatBounds|null} + */ + getDayBounds(dayKey) { + return this.dayBounds.get(dayKey) || null + } + + /** + * Get bounds for the full trip + * @returns {maplibregl.LngLatBounds|null} + */ + getFullBounds() { + return this.fullBounds + } + + /** + * Get color for a specific day + * @param {string} dayKey + * @returns {string|null} + */ + getDayColor(dayKey) { + return this.dayColors.get(dayKey) || null + } + + /** + * Get all day keys that have routes + * @returns {string[]} + */ + getDayKeys() { + return Array.from(this.dayLayers.keys()).sort() + } + + /** + * Register click and hover interactions on all day layers + * @param {Object} callbacks - { onDayClick: (dayKey) => void } + */ + setupInteractions(callbacks) { + this.interactionHandlers = [] + this.hoverMarkers = [] + this.hoveredDayKey = null + + for (const [dayKey, layerId] of this.dayLayers) { + const clickHandler = (e) => { + const feature = e.features?.[0] + if (!feature) return + const key = feature.properties.dayKey + if (key && callbacks.onDayClick) { + callbacks.onDayClick(key) + } + } + + const mouseEnterHandler = (e) => { + const feature = e.features?.[0] + if (!feature) return + + this.map.getCanvas().style.cursor = "pointer" + this.hoveredDayKey = dayKey + + // Highlight hovered day, dim others + for (const [key, lid] of this.dayLayers) { + if (!this.map.getLayer(lid)) continue + if (key === dayKey) { + this.map.setPaintProperty(lid, "line-opacity", 1.0) + this.map.setPaintProperty(lid, "line-width", 5) + } else { + this.map.setPaintProperty(lid, "line-opacity", 0.25) + this.map.setPaintProperty(lid, "line-width", 2) + } + } + + // Add start/end markers for the hovered segment + this.removeHoverMarkers() + const coords = feature.geometry.coordinates + if (coords && coords.length >= 2) { + const startCoord = coords[0] + const endCoord = coords[coords.length - 1] + + this.hoverMarkers.push( + this.createCircleMarker(startCoord, "#22c55e", "Start"), + ) + this.hoverMarkers.push( + this.createCircleMarker(endCoord, "#ef4444", "End"), + ) + } + } + + const mouseLeaveHandler = () => { + this.map.getCanvas().style.cursor = "" + this.hoveredDayKey = null + this.removeHoverMarkers() + + // Restore paint state + if (this.selectedDay) { + this.selectDay(this.selectedDay) + } else { + this.selectAllDays() + } + } + + this.map.on("click", layerId, clickHandler) + this.map.on("mouseenter", layerId, mouseEnterHandler) + this.map.on("mouseleave", layerId, mouseLeaveHandler) + + this.interactionHandlers.push( + { type: "click", layerId, handler: clickHandler }, + { type: "mouseenter", layerId, handler: mouseEnterHandler }, + { type: "mouseleave", layerId, handler: mouseLeaveHandler }, + ) + } + } + + /** + * Create a small circle marker with a label + * @param {number[]} lngLat - [lng, lat] + * @param {string} color - CSS color + * @param {string} label - "Start" or "End" + * @returns {maplibregl.Marker} + */ + createCircleMarker(lngLat, color, label) { + const el = document.createElement("div") + el.style.cssText = ` + width: 10px; height: 10px; border-radius: 50%; + background: ${color}; border: 2px solid white; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + ` + el.title = label + + return new maplibregl.Marker({ element: el }) + .setLngLat(lngLat) + .addTo(this.map) + } + + /** + * Remove hover markers from the map + */ + removeHoverMarkers() { + for (const marker of this.hoverMarkers) { + marker.remove() + } + this.hoverMarkers = [] + } + + /** + * Remove all interaction event listeners + */ + removeInteractions() { + if (this.interactionHandlers) { + for (const { type, layerId, handler } of this.interactionHandlers) { + this.map.off(type, layerId, handler) + } + this.interactionHandlers = [] + } + this.removeHoverMarkers() + this.hoveredDayKey = null + } + + /** + * Remove all day route layers and sources + */ + remove() { + this.removeInteractions() + for (const [, layerId] of this.dayLayers) { + if (this.map.getLayer(layerId)) { + this.map.removeLayer(layerId) + } + } + + for (const [, sourceId] of this.daySources) { + if (this.map.getSource(sourceId)) { + this.map.removeSource(sourceId) + } + } + + this.daySources.clear() + this.dayLayers.clear() + this.dayColors.clear() + this.dayBounds.clear() + this.fullBounds = null + this.selectedDay = null + } +} diff --git a/app/javascript/maps_maplibre/managers/timeline_manager.js b/app/javascript/maps_maplibre/managers/timeline_manager.js index f058fb390..eeafe6391 100644 --- a/app/javascript/maps_maplibre/managers/timeline_manager.js +++ b/app/javascript/maps_maplibre/managers/timeline_manager.js @@ -305,6 +305,22 @@ export class TimelineManager { return false } + /** + * Navigate to a specific day by key + * @param {string} dayKey - Day key like '2025-01-15' + * @returns {boolean} Whether navigation was successful + */ + goToDay(dayKey) { + const index = this.availableDays.indexOf(dayKey) + if (index === -1 || index === this.currentDayIndex) return false + + this.currentDayIndex = index + this.buildMinuteIndex() + this.cycleIndex = 0 + this.pinnedPoint = null + return true + } + /** * Navigate to next day * @returns {boolean} Whether navigation was successful @@ -498,6 +514,24 @@ export class TimelineManager { return null } + /** + * Get timestamp from point (handles different point formats) + * @param {Object} point - Point object + * @returns {*} Timestamp value or null + */ + getTimestamp(point) { + return this._getTimestamp(point) + } + + /** + * Get points for a specific day + * @param {string} dayKey - Day key like '2025-01-15' + * @returns {Array} Points for that day, or empty array + */ + getPointsForDay(dayKey) { + return this.pointsByDay[dayKey] || [] + } + // Private helpers /** diff --git a/app/models/area.rb b/app/models/area.rb index 589ccd9dc..f646774be 100644 --- a/app/models/area.rb +++ b/app/models/area.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Area < ApplicationRecord + include Notable + reverse_geocoded_by :latitude, :longitude belongs_to :user diff --git a/app/models/concerns/notable.rb b/app/models/concerns/notable.rb new file mode 100644 index 000000000..b7eefb4dd --- /dev/null +++ b/app/models/concerns/notable.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Notable + extend ActiveSupport::Concern + + included do + has_many :notes, as: :attachable, dependent: :destroy + end +end diff --git a/app/models/note.rb b/app/models/note.rb new file mode 100644 index 000000000..97ff58a01 --- /dev/null +++ b/app/models/note.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +class Note < ApplicationRecord + include Nearable + + ALLOWED_ATTACHABLE_TYPES = %w[Trip Area Visit Place Point].freeze + + has_rich_text :body + + belongs_to :user + belongs_to :attachable, polymorphic: true, optional: true + + before_validation :build_lonlat_from_coords, if: -> { @latitude.present? && @longitude.present? } + + validates :noted_at, presence: true + validates :attachable_type, inclusion: { in: ALLOWED_ATTACHABLE_TYPES }, allow_nil: true + validates :attachable, presence: true, if: -> { attachable_type.present? || attachable_id.present? } + + validate :unique_date_per_attachable + validate :date_within_attachable_range + validate :attachable_belongs_to_user + + scope :standalone, -> { where(attachable_id: nil) } + scope :attached, -> { where.not(attachable_id: nil) } + scope :for_trip_day, ->(trip, date) { where(attachable: trip).where('CAST(noted_at AS date) = ?', date) } + scope :for_date, ->(date) { where('CAST(noted_at AS date) = ?', date) } + scope :in_date_range, ->(start_at, end_at) { where(noted_at: start_at..end_at) } + scope :ordered, -> { order(noted_at: :desc) } + scope :for_user, ->(user) { where(user: user) } + + def date + noted_at&.to_date + end + + def date=(val) + return if val.blank? + + self.noted_at = val.to_date.to_datetime.noon + end + + def latitude + lonlat&.y + end + + def longitude + lonlat&.x + end + + def latitude=(val) + @latitude = val.presence&.to_f + end + + def longitude=(val) + @longitude = val.presence&.to_f + end + + private + + def build_lonlat_from_coords + self.lonlat = "POINT(#{@longitude} #{@latitude})" + end + + def unique_date_per_attachable + return if noted_at.blank? || attachable_id.blank? + + scope = self.class.where(attachable_type: attachable_type, attachable_id: attachable_id) + .where('CAST(noted_at AS date) = ?', noted_at.to_date) + scope = scope.where.not(id: id) if persisted? + + errors.add(:date, 'has already been taken') if scope.exists? + end + + def date_within_attachable_range + return unless attachable.is_a?(Trip) + return if date.blank? || attachable.blank? + return if attachable.started_at.blank? || attachable.ended_at.blank? + return unless date < attachable.started_at.to_date || date > attachable.ended_at.to_date + + errors.add(:date, 'must be within the trip date range') + end + + def attachable_belongs_to_user + return if attachable.blank? + return unless attachable.respond_to?(:user_id) + return if attachable.user_id == user_id + + errors.add(:attachable, 'must belong to the same user') + end +end diff --git a/app/models/place.rb b/app/models/place.rb index af89a661c..6735fa15f 100644 --- a/app/models/place.rb +++ b/app/models/place.rb @@ -4,6 +4,7 @@ class Place < ApplicationRecord include Nearable include Distanceable include Taggable + include Notable DEFAULT_NAME = 'Suggested place' diff --git a/app/models/point.rb b/app/models/point.rb index cdc017121..d5b5f24d3 100644 --- a/app/models/point.rb +++ b/app/models/point.rb @@ -4,6 +4,7 @@ class Point < ApplicationRecord include Nearable include Distanceable include Archivable + include Notable belongs_to :import, optional: true, counter_cache: true belongs_to :visit, optional: true @@ -74,7 +75,6 @@ def country_name private - # rubocop:disable Metrics/MethodLength Metrics/AbcSize def broadcast_coordinates if user.safe_settings.live_map_enabled PointsChannel.broadcast_to( @@ -94,7 +94,6 @@ def broadcast_coordinates broadcast_to_family if should_broadcast_to_family? end - # rubocop:enable Metrics/MethodLength def should_broadcast_to_family? return false unless DawarichSettings.family_feature_enabled? diff --git a/app/models/trip.rb b/app/models/trip.rb index 3b882f4bc..aa0553af9 100644 --- a/app/models/trip.rb +++ b/app/models/trip.rb @@ -3,8 +3,9 @@ class Trip < ApplicationRecord include Calculateable include DistanceConvertible + include Notable - has_rich_text :notes + has_rich_text :description belongs_to :user diff --git a/app/models/user.rb b/app/models/user.rb index 20301ac75..9ab9c5911 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -22,6 +22,7 @@ class User < ApplicationRecord has_many :tracks, dependent: :destroy has_many :raw_data_archives, class_name: 'Points::RawDataArchive', dependent: :destroy has_many :digests, class_name: 'Users::Digest', dependent: :destroy + has_many :notes, dependent: :destroy after_create :create_api_key after_commit :activate, on: :create, if: -> { DawarichSettings.self_hosted? } diff --git a/app/models/visit.rb b/app/models/visit.rb index 936fdc7dd..6f9f63c69 100644 --- a/app/models/visit.rb +++ b/app/models/visit.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Visit < ApplicationRecord + include Notable + belongs_to :area, optional: true belongs_to :place, optional: true belongs_to :user diff --git a/app/serializers/api/note_serializer.rb b/app/serializers/api/note_serializer.rb new file mode 100644 index 000000000..35f533c6e --- /dev/null +++ b/app/serializers/api/note_serializer.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class Api::NoteSerializer + def initialize(note) + @note = note + end + + def call + { + id: note.id, + title: note.title, + body: note.body&.to_plain_text, + latitude: note.latitude&.to_f, + longitude: note.longitude&.to_f, + attachable_type: note.attachable_type, + attachable_id: note.attachable_id, + date: note.date, + noted_at: note.noted_at, + created_at: note.created_at, + updated_at: note.updated_at + } + end + + private + + attr_reader :note +end diff --git a/app/views/trips/_countries.html.erb b/app/views/trips/_countries.html.erb index c0a6cf53e..5a0d67976 100644 --- a/app/views/trips/_countries.html.erb +++ b/app/views/trips/_countries.html.erb @@ -1,51 +1,20 @@ -
-
-
-
Distance
-
<%= trip.distance_in_unit(distance_unit).round %> <%= distance_unit %>
-
-
-
-
-
Duration
-
<%= trip_duration(trip) %>
-
-
-
-
-
Countries
-
- <% if trip.visited_countries.any? %> - <%= trip.visited_countries.count %> - <% else %> - - <% end %> -
-
-
-
- - - - +

+ <% if trip.visited_countries.any? %> +
+ <% trip.visited_countries.sort.each do |country| %> + <%= country_flag(country) %> + <% end %> +
+ <% end %> + diff --git a/app/views/trips/_form.html.erb b/app/views/trips/_form.html.erb index 01df51ab3..0b5ee27f4 100644 --- a/app/views/trips/_form.html.erb +++ b/app/views/trips/_form.html.erb @@ -63,8 +63,8 @@
- <%= form.label :notes %> - <%= form.rich_text_area :notes, class: 'trix-content-editor' %> + <%= form.label :description %> + <%= form.rich_text_area :description, class: 'trix-content-editor' %>
diff --git a/app/views/trips/_path.html.erb b/app/views/trips/_path.html.erb index b799e02f4..3bf0abaae 100644 --- a/app/views/trips/_path.html.erb +++ b/app/views/trips/_path.html.erb @@ -1,20 +1,20 @@ <% if trip.path.present? %> -
-
+
+
+ + <%# Day selector bar %> +
+
<% else %> -
+

Trip path is being calculated...

diff --git a/app/views/trips/_timeline_panel.html.erb b/app/views/trips/_timeline_panel.html.erb new file mode 100644 index 000000000..d3b9b0cc2 --- /dev/null +++ b/app/views/trips/_timeline_panel.html.erb @@ -0,0 +1,102 @@ +<%# Timeline Panel - Bottom scrubber for navigating through trip location data by time %> + diff --git a/app/views/trips/_trip.html.erb b/app/views/trips/_trip.html.erb index d21707255..074ea0b0f 100644 --- a/app/views/trips/_trip.html.erb +++ b/app/views/trips/_trip.html.erb @@ -12,12 +12,9 @@
+ data-controller="trip-maplibre-preview" + data-trip-maplibre-preview-path-value="<%= trip.path.coordinates.to_json %>" + data-trip-maplibre-preview-map-style-value="<%= current_user.safe_settings.settings['maps_maplibre_style'] || 'light' %>">
<% else %>
diff --git a/app/views/trips/notes/_empty.html.erb b/app/views/trips/notes/_empty.html.erb new file mode 100644 index 000000000..c217239d7 --- /dev/null +++ b/app/views/trips/notes/_empty.html.erb @@ -0,0 +1,26 @@ + +
+ +
+ + +
diff --git a/app/views/trips/notes/_form.html.erb b/app/views/trips/notes/_form.html.erb new file mode 100644 index 000000000..4c8042348 --- /dev/null +++ b/app/views/trips/notes/_form.html.erb @@ -0,0 +1,32 @@ + + <%= form_with( + model: note, + url: note.persisted? ? trip_note_path(trip, note) : trip_notes_path(trip), + class: "space-y-3" + ) do |form| %> + <%= form.hidden_field :date, value: note.date %> + + <% if note.errors.any? %> +
+ <%= note.errors.full_messages.join(', ') %> +
+ <% end %> + +
+ +
+ +
+ <%= form.submit note.persisted? ? "Update note" : "Save note", + class: "btn btn-primary btn-sm" %> + +
+ <% end %> +
diff --git a/app/views/trips/notes/_note.html.erb b/app/views/trips/notes/_note.html.erb new file mode 100644 index 000000000..2696814f5 --- /dev/null +++ b/app/views/trips/notes/_note.html.erb @@ -0,0 +1,49 @@ + +
+
+ <%= note.body %> +
+
+ + <%= button_to "Delete", + trip_note_path(trip, note), + method: :delete, + class: "btn btn-xs btn-ghost text-error", + data: { turbo_confirm: "Delete this note?" } %> +
+
+ + +
diff --git a/app/views/trips/show.html.erb b/app/views/trips/show.html.erb index 023ccf422..b14150a84 100644 --- a/app/views/trips/show.html.erb +++ b/app/views/trips/show.html.erb @@ -2,28 +2,134 @@ <%= turbo_stream_from "trip_#{@trip.id}" %> -
-
-
-
- <%= render "trips/path", trip: @trip, current_user: current_user %> -
-
-
-

<%= @trip.name %>

-

- <%= human_date(@trip.started_at) %> - <%= human_date(@trip.ended_at) %> -

+
- <%= render "trips/countries", trip: @trip, current_user: current_user, distance_unit: current_user.safe_settings.distance_unit %> + <%# Side-by-side layout: map left, content right %> +
+ <%# Left: Map (sticky on desktop) %> +
+ <% if @trip.path.present? %> +
+ + <%= render "trips/timeline_panel" %> +
+ <% else %> +
+
+

Trip path is being calculated...

+
+
+ <% end %> +
+ + <%# Right: Scrollable content panel %> +
+ <%# Trip header %> +
+

<%= @trip.name %>

+

+ <%= human_date(@trip.started_at) %> - <%= human_date(@trip.ended_at) %> +

+ + <%= render "trips/countries", trip: @trip, current_user: current_user, distance_unit: current_user.safe_settings.distance_unit %> +
-
- <%= @trip.notes.body %> + <%# Map tools toolbar %> +
+ <% if current_user.immich_integration_configured? || current_user.photoprism_integration_configured? %> + + <% end %> + + + + +
+ + <%# Accordion days %> +
+ + <% (@trip.started_at.in_time_zone(@timezone).to_date..@trip.ended_at.in_time_zone(@timezone).to_date).each do |date| %> + <% day_key = date.strftime('%Y-%m-%d') %> + <% stats = @day_stats[date] %> +
+ + + <%= date.strftime('%b %-d, %A') %> + <% if stats %> + + <%= stats[:first_time].strftime('%H:%M') %> – <%= stats[:last_time].strftime('%H:%M') %> + + + <% day_distance = Trip.convert_distance(stats[:distance_m], @distance_unit) %> + <% if day_distance < 1 %> + < 1 <%= @distance_unit %> + <% else %> + <%= number_with_precision(day_distance, precision: 1) %> <%= @distance_unit %> + <% end %> + + <% else %> + No data + <% end %> + +
+ <% note = @day_notes[date] %> + <% if note %> + <%= render "trips/notes/note", note: note, trip: @trip %> + <% else %> + <%= render "trips/notes/empty", trip: @trip, date: date %> + <% end %> +
+
+ <% end %> +
+ + <%# Trip description %> + <% if @trip.description.body.present? %> +
+

Trip Notes

+
+ <%= @trip.description.body %> +
+ <% end %> - - <% if @photo_previews.any? %> + <%# Photos %> + <% if @photo_previews.any? %> +
+

Photos

<% @photo_previews.each_slice(3) do |slice| %>
<% slice.each do |photo| %> @@ -37,31 +143,29 @@ <% end %>
<% end %> - <% end %> +
+ <% end %> - <% if @photo_sources.any? %> -
- <% @photo_sources.each do |source| %> - <%= link_to "More photos on #{source}", photo_search_url(source, current_user.settings, @trip.started_at, @trip.ended_at), class: "btn btn-primary mt-2", target: '_blank' %> - <% end %> -
- <% end %> -
-
-
+ <% if @photo_sources.any? %> +
+ <% @photo_sources.each do |source| %> + <%= link_to "More photos on #{source}", photo_search_url(source, current_user.settings, @trip.started_at, @trip.ended_at), class: "btn btn-primary mt-2", target: '_blank' %> + <% end %> +
+ <% end %> - -
-
- <%= link_to "Edit this trip", edit_trip_path(@trip), class: "btn" %> - <%= link_to "Destroy this trip", - trip_path(@trip), - data: { - turbo_confirm: "Are you sure?", - turbo_method: :delete - }, - class: "btn" %> - <%= link_to "Back to trips", trips_path, class: "btn" %> + <%# Action buttons %> +
+ <%= link_to "Edit this trip", edit_trip_path(@trip), class: "btn" %> + <%= link_to "Destroy this trip", + trip_path(@trip), + data: { + turbo_confirm: "Are you sure?", + turbo_method: :delete + }, + class: "btn" %> + <%= link_to "Back to trips", trips_path, class: "btn" %> +
diff --git a/config/initializers/rails_icons.rb b/config/initializers/rails_icons.rb index b0d79e401..a414d67b3 100644 --- a/config/initializers/rails_icons.rb +++ b/config/initializers/rails_icons.rb @@ -11,4 +11,9 @@ # config.libraries.lucide.outline.default.css = "size-6" # config.libraries.lucide.outline.default.stroke_width = "1.5" # config.libraries.lucide.outline.default.data = {} + + # Flags library: use landscape (4x3) as default variant + config.libraries.flags.default_variant = 'landscape' + + config.libraries.flags.landscape.default.css = 'inline-block rounded-sm h-4 w-auto' end diff --git a/config/routes.rb b/config/routes.rb index 478a4a4b5..e71826695 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -62,7 +62,9 @@ resources :visits, only: %i[index update] resources :places, only: %i[index destroy] resources :exports, only: %i[index create destroy] - resources :trips + resources :trips do + resources :notes, controller: 'trips/notes', only: %i[create update destroy] + end resources :tags, except: [:show] # Family management routes (only if feature is enabled) @@ -228,6 +230,8 @@ resources :locations, only: [:index] end + resources :notes, only: %i[index show create update destroy] + post 'subscriptions/callback', to: 'subscriptions#callback' end end diff --git a/db/migrate/20260207075817_create_notes_and_rename_trips_rich_text.rb b/db/migrate/20260207075817_create_notes_and_rename_trips_rich_text.rb new file mode 100644 index 000000000..6a73855a5 --- /dev/null +++ b/db/migrate/20260207075817_create_notes_and_rename_trips_rich_text.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class CreateNotesAndRenameTripsRichText < ActiveRecord::Migration[8.0] + def up + create_table :notes do |t| + t.references :user, null: false, foreign_key: true + t.string :title + t.st_point :lonlat, geographic: true + t.string :attachable_type + t.bigint :attachable_id + t.datetime :noted_at + t.timestamps + end + + add_index :notes, %i[attachable_type attachable_id] + add_index :notes, :lonlat, using: :gist + add_index :notes, %i[user_id noted_at] + + execute <<-SQL.squish + CREATE UNIQUE INDEX index_notes_on_attachable_and_noted_date + ON notes (attachable_type, attachable_id, (CAST(noted_at AS date))) + WHERE attachable_id IS NOT NULL + SQL + + # Rename Trip's has_rich_text :notes to :description + execute <<-SQL.squish + UPDATE action_text_rich_texts + SET name = 'description' + WHERE record_type = 'Trip' AND name = 'notes' + SQL + end + + def down + execute <<-SQL.squish + UPDATE action_text_rich_texts + SET name = 'notes' + WHERE record_type = 'Trip' AND name = 'description' + SQL + + drop_table :notes + end +end diff --git a/db/migrate/20260208223255_fix_countries_with_missing_iso_codes.rb b/db/migrate/20260208223255_fix_countries_with_missing_iso_codes.rb new file mode 100644 index 000000000..2c3ea8d2a --- /dev/null +++ b/db/migrate/20260208223255_fix_countries_with_missing_iso_codes.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +class FixCountriesWithMissingIsoCodes < ActiveRecord::Migration[8.0] + # Natural Earth data uses "-99" as a placeholder for countries/territories + # that lack official ISO codes. Many of these do have well-known codes that + # we can assign. The remaining entries (disputed/unclaimed territories like + # Siachen Glacier, Bir Tawil, etc.) are genuinely codeless and stay as "-99". + CORRECTIONS = { + 'France' => { iso_a2: 'FR', iso_a3: 'FRA' }, + 'Norway' => { iso_a2: 'NO', iso_a3: 'NOR' }, + 'Kosovo' => { iso_a2: 'XK', iso_a3: 'XKX' }, + 'Somaliland' => { iso_a2: 'SO', iso_a3: 'SOM' }, + 'Northern Cyprus' => { iso_a2: 'CY', iso_a3: 'CYP' }, + 'Dhekelia Sovereign Base Area' => { iso_a2: 'GB', iso_a3: 'GBR' }, + 'Akrotiri Sovereign Base Area' => { iso_a2: 'GB', iso_a3: 'GBR' }, + 'US Naval Base Guantanamo Bay' => { iso_a2: 'US', iso_a3: 'USA' }, + 'Cyprus No Mans Area' => { iso_a2: 'CY', iso_a3: 'CYP' }, + 'Baykonur Cosmodrome' => { iso_a2: 'KZ', iso_a3: 'KAZ' }, + 'Brazilian Island' => { iso_a2: 'BR', iso_a3: 'BRA' }, + 'Indian Ocean Territories' => { iso_a2: 'AU', iso_a3: 'AUS' }, + 'Coral Sea Islands' => { iso_a2: 'AU', iso_a3: 'AUS' }, + 'Clipperton Island' => { iso_a2: 'FR', iso_a3: 'FRA' }, + 'Ashmore and Cartier Islands' => { iso_a2: 'AU', iso_a3: 'AUS' } + }.freeze + + def up + CORRECTIONS.each do |name, codes| + execute(sanitize_sql( + [ + "UPDATE countries SET iso_a2 = ?, iso_a3 = ? WHERE name = ? AND iso_a2 = '-99'", + codes[:iso_a2], codes[:iso_a3], name + ] + )) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end + + private + + def sanitize_sql(array) + ActiveRecord::Base.sanitize_sql_array(array) + end +end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb new file mode 100644 index 000000000..225d765c6 --- /dev/null +++ b/spec/factories/notes.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :note do + user + noted_at { Time.current } + body { FFaker::Lorem.sentence } + + trait :standalone do + title { FFaker::Lorem.phrase } + latitude { FFaker::Geolocation.lat } + longitude { FFaker::Geolocation.lng } + end + + trait :trip_day do + attachable { association(:trip, user: user) } + noted_at { attachable.started_at.to_date.to_datetime.noon } + end + end +end diff --git a/spec/factories/trips.rb b/spec/factories/trips.rb index 5986e8823..bd9c9f643 100644 --- a/spec/factories/trips.rb +++ b/spec/factories/trips.rb @@ -6,7 +6,7 @@ name { FFaker::Lorem.word } started_at { DateTime.new(2024, 11, 27, 17, 16, 21) } ended_at { DateTime.new(2024, 11, 29, 17, 16, 21) } - notes { FFaker::Lorem.sentence } + description { FFaker::Lorem.sentence } distance { 100 } path { 'LINESTRING(1 1, 2 2, 3 3)' } diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb new file mode 100644 index 000000000..143c50a22 --- /dev/null +++ b/spec/models/note_spec.rb @@ -0,0 +1,210 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Note, type: :model do + describe 'associations' do + it { is_expected.to belong_to(:user) } + it { is_expected.to belong_to(:attachable).optional } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:noted_at) } + + context 'uniqueness of date per attachable' do + let(:user) { create(:user) } + let(:trip) { create(:trip, user: user) } + let!(:existing_note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + end + + it 'does not allow duplicate dates for the same attachable' do + duplicate = build(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + expect(duplicate).not_to be_valid + expect(duplicate.errors[:date]).to include('has already been taken') + end + + it 'allows the same date for different attachables' do + other_trip = create(:trip, user: user, started_at: trip.started_at, ended_at: trip.ended_at) + note = build(:note, user: user, attachable: other_trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + expect(note).to be_valid + end + + it 'allows multiple standalone notes on the same date' do + note1 = create(:note, user: user, noted_at: Time.current) + note2 = build(:note, user: user, noted_at: Time.current) + expect(note1).to be_valid + expect(note2).to be_valid + end + end + + context 'attachable belongs to user' do + let(:user) { create(:user) } + let(:other_user) { create(:user) } + let(:trip) { create(:trip, user: user) } + let(:other_trip) { create(:trip, user: other_user) } + + it 'is valid when attachable belongs to the same user' do + note = build(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + expect(note).to be_valid + end + + it 'is invalid when attachable belongs to a different user' do + note = build(:note, user: user, attachable: other_trip, + noted_at: other_trip.started_at.to_date.to_datetime.noon) + expect(note).not_to be_valid + expect(note.errors[:attachable]).to include('must belong to the same user') + end + + it 'is valid when attachable is blank (standalone note)' do + note = build(:note, user: user, noted_at: Time.current) + expect(note).to be_valid + end + end + + context 'date within trip range' do + let(:user) { create(:user) } + let(:trip) { create(:trip, user: user) } + + it 'is valid when date is within trip range' do + note = build(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + expect(note).to be_valid + end + + it 'is invalid when date is before trip start' do + note = build(:note, user: user, attachable: trip, + noted_at: (trip.started_at.to_date - 1.day).to_datetime.noon) + expect(note).not_to be_valid + expect(note.errors[:date]).to include('must be within the trip date range') + end + + it 'is invalid when date is after trip end' do + note = build(:note, user: user, attachable: trip, + noted_at: (trip.ended_at.to_date + 1.day).to_datetime.noon) + expect(note).not_to be_valid + expect(note.errors[:date]).to include('must be within the trip date range') + end + end + end + + describe '#date' do + let(:user) { create(:user) } + + it 'derives date from noted_at' do + note = build(:note, user: user, noted_at: DateTime.new(2025, 3, 15, 14, 30)) + expect(note.date).to eq(Date.new(2025, 3, 15)) + end + end + + describe '#date=' do + let(:user) { create(:user) } + + it 'sets noted_at to noon on the given date' do + note = Note.new(user: user) + note.date = '2025-03-15' + expect(note.noted_at).to eq(Date.new(2025, 3, 15).to_datetime.noon) + end + end + + describe 'scopes' do + let(:user) { create(:user) } + let(:trip) { create(:trip, user: user) } + + describe '.standalone' do + let!(:standalone_note) { create(:note, user: user, noted_at: Time.current) } + let!(:attached_note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + end + + it 'returns only notes without an attachable' do + expect(described_class.standalone).to include(standalone_note) + expect(described_class.standalone).not_to include(attached_note) + end + end + + describe '.attached' do + let!(:standalone_note) { create(:note, user: user, noted_at: Time.current) } + let!(:attached_note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + end + + it 'returns only notes with an attachable' do + expect(described_class.attached).to include(attached_note) + expect(described_class.attached).not_to include(standalone_note) + end + end + + describe '.for_trip_day' do + let!(:trip_note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + end + + it 'returns notes for a specific trip and date' do + result = described_class.for_trip_day(trip, trip.started_at.to_date) + expect(result).to include(trip_note) + end + end + end + + describe 'rich text' do + let(:user) { create(:user) } + let(:note) { create(:note, user: user, body: 'A wonderful day exploring the city', noted_at: Time.current) } + + it 'has rich text body' do + expect(note.body).to be_an(ActionText::RichText) + expect(note.body.to_plain_text).to eq('A wonderful day exploring the city') + end + end + + describe 'notable concern' do + let(:user) { create(:user) } + let(:trip) { create(:trip, user: user) } + let!(:note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + end + + it 'destroys notes when attachable is destroyed' do + expect { trip.destroy }.to change(Note, :count).by(-1) + end + end + + describe 'attachable_type validation' do + let(:user) { create(:user) } + + it 'allows valid attachable types' do + %w[Trip Area Visit Place Point].each do |type| + note = build(:note, user: user, noted_at: Time.current) + note.attachable_type = type + note.valid? + expect(note.errors[:attachable_type]).to be_empty + end + end + + it 'rejects invalid attachable types' do + note = build(:note, user: user, noted_at: Time.current, attachable_type: 'User') + expect(note).not_to be_valid + expect(note.errors[:attachable_type]).to be_present + end + + it 'allows nil attachable_type' do + note = build(:note, user: user, noted_at: Time.current) + expect(note).to be_valid + end + + it 'requires attachable to exist when attachable_type is set' do + note = build(:note, user: user, noted_at: Time.current, + attachable_type: 'Trip', attachable_id: 999_999) + expect(note).not_to be_valid + expect(note.errors[:attachable]).to be_present + end + end +end diff --git a/spec/requests/api/v1/notes_spec.rb b/spec/requests/api/v1/notes_spec.rb new file mode 100644 index 000000000..15575a45a --- /dev/null +++ b/spec/requests/api/v1/notes_spec.rb @@ -0,0 +1,221 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe '/api/v1/notes', type: :request do + let(:user) { create(:user) } + let(:headers) { { 'Authorization' => "Bearer #{user.api_key}" } } + + describe 'GET /index' do + let!(:note) { create(:note, user: user, noted_at: Time.current) } + + it 'renders a successful response' do + get api_v1_notes_url, headers: headers + expect(response).to be_successful + end + + it 'returns notes for the current user' do + get api_v1_notes_url, headers: headers + json = JSON.parse(response.body) + expect(json.length).to eq(1) + expect(json.first['id']).to eq(note.id) + end + + context 'with filtering params' do + let(:trip) { create(:trip, user: user) } + let!(:trip_note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon) + end + + it 'filters by attachable_type' do + get api_v1_notes_url, headers: headers, params: { attachable_type: 'Trip' } + json = JSON.parse(response.body) + expect(json.length).to eq(1) + expect(json.first['id']).to eq(trip_note.id) + end + + it 'filters standalone notes' do + get api_v1_notes_url, headers: headers, params: { standalone: 'true' } + json = JSON.parse(response.body) + expect(json.length).to eq(1) + expect(json.first['id']).to eq(note.id) + end + end + + it 'returns 401 without auth' do + get api_v1_notes_url + expect(response).to have_http_status(:unauthorized) + end + end + + describe 'GET /show' do + let(:note) { create(:note, user: user, noted_at: Time.current) } + + it 'renders a successful response' do + get api_v1_note_url(note), headers: headers + expect(response).to be_successful + end + + it 'returns the note' do + get api_v1_note_url(note), headers: headers + json = JSON.parse(response.body) + expect(json['id']).to eq(note.id) + end + + it 'returns 404 for another user note' do + other_note = create(:note, noted_at: Time.current) + get api_v1_note_url(other_note), headers: headers + expect(response).to have_http_status(:not_found) + end + end + + describe 'POST /create' do + context 'with valid parameters' do + let(:valid_params) do + { note: { body: 'A test note', noted_at: Time.current.iso8601 } } + end + + it 'creates a new Note' do + expect do + post api_v1_notes_url, headers: headers, params: valid_params + end.to change(Note, :count).by(1) + end + + it 'returns created status' do + post api_v1_notes_url, headers: headers, params: valid_params + expect(response).to have_http_status(:created) + end + end + + context 'with attachable' do + let(:trip) { create(:trip, user: user) } + + it 'creates a note attached to a trip' do + params = { + note: { + body: 'Trip note', + noted_at: trip.started_at.to_date.to_datetime.noon.iso8601, + attachable_type: 'Trip', + attachable_id: trip.id + } + } + + expect do + post api_v1_notes_url, headers: headers, params: params + end.to change(Note, :count).by(1) + + expect(response).to have_http_status(:created) + end + end + + context 'with cross-user attachable' do + let(:other_user) { create(:user) } + let(:other_trip) { create(:trip, user: other_user) } + + it 'rejects note attached to another user trip' do + params = { + note: { + body: 'Sneaky note', + noted_at: other_trip.started_at.to_date.to_datetime.noon.iso8601, + attachable_type: 'Trip', + attachable_id: other_trip.id + } + } + + expect do + post api_v1_notes_url, headers: headers, params: params + end.not_to change(Note, :count) + + expect(response).to have_http_status(:unprocessable_content) + json = JSON.parse(response.body) + expect(json['errors']).to include('Attachable must belong to the same user') + end + end + + context 'with invalid parameters' do + it 'returns 422 when noted_at is missing' do + post api_v1_notes_url, headers: headers, params: { note: { body: 'No date' } } + expect(response).to have_http_status(:unprocessable_content) + end + end + end + + describe 'PATCH /update' do + let(:note) { create(:note, user: user, body: 'Original', noted_at: Time.current) } + + context 'with valid parameters' do + it 'updates the note' do + patch api_v1_note_url(note), headers: headers, + params: { note: { body: 'Updated' } } + expect(response).to have_http_status(:ok) + json = JSON.parse(response.body) + expect(json['body']).to eq('Updated') + end + end + + context 'with invalid parameters' do + it 'returns 422' do + patch api_v1_note_url(note), headers: headers, + params: { note: { noted_at: nil } } + expect(response).to have_http_status(:unprocessable_content) + end + end + + context 'with another user note' do + let(:other_note) { create(:note, noted_at: Time.current) } + + it 'returns 404' do + patch api_v1_note_url(other_note), headers: headers, + params: { note: { body: 'Hijack' } } + expect(response).to have_http_status(:not_found) + end + end + end + + describe 'DELETE /destroy' do + let!(:note) { create(:note, user: user, noted_at: Time.current) } + + it 'destroys the note' do + expect do + delete api_v1_note_url(note), headers: headers + end.to change(Note, :count).by(-1) + end + + it 'returns ok status' do + delete api_v1_note_url(note), headers: headers + expect(response).to have_http_status(:ok) + end + + context 'with another user note' do + let!(:other_note) { create(:note, noted_at: Time.current) } + + it 'returns 404' do + expect do + delete api_v1_note_url(other_note), headers: headers + end.not_to change(Note, :count) + + expect(response).to have_http_status(:not_found) + end + end + end + + describe 'POST /create with invalid attachable_type' do + it 'rejects an invalid attachable_type' do + params = { + note: { + body: 'Sneaky note', + noted_at: Time.current.iso8601, + attachable_type: 'User', + attachable_id: user.id + } + } + + expect do + post api_v1_notes_url, headers: headers, params: params + end.not_to change(Note, :count) + + expect(response).to have_http_status(:unprocessable_content) + end + end +end diff --git a/spec/requests/trips/notes_spec.rb b/spec/requests/trips/notes_spec.rb new file mode 100644 index 000000000..d70e93b27 --- /dev/null +++ b/spec/requests/trips/notes_spec.rb @@ -0,0 +1,174 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe '/trips/:trip_id/notes', type: :request do + let(:user) { create(:user) } + let(:trip) { create(:trip, user: user) } + + before do + stub_request(:any, 'https://api.github.com/repos/Freika/dawarich/tags') + .to_return(status: 200, body: '[{"name": "1.0.0"}]', headers: {}) + + sign_in user + end + + describe 'POST /trips/:trip_id/notes' do + let(:valid_params) do + { + note: { + date: trip.started_at.to_date, + body: 'Great day exploring!' + } + } + end + + context 'with valid parameters' do + it 'creates a new note' do + expect do + post trip_notes_url(trip), params: valid_params + end.to change(Note, :count).by(1) + end + + it 'redirects to the trip for HTML format' do + post trip_notes_url(trip), params: valid_params + expect(response).to redirect_to(trip) + end + + it 'responds with turbo stream for turbo requests' do + post trip_notes_url(trip), params: valid_params, + headers: { Accept: 'text/vnd.turbo-stream.html' } + expect(response.media_type).to eq('text/vnd.turbo-stream.html') + end + end + + context 'with find_or_initialize (idempotent create)' do + let!(:existing_note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon, body: 'Old note') + end + + it 'updates existing note instead of creating a duplicate' do + expect do + post trip_notes_url(trip), params: valid_params + end.not_to change(Note, :count) + + existing_note.reload + expect(existing_note.body.to_plain_text).to eq('Great day exploring!') + end + end + + context 'with date outside trip range' do + let(:invalid_params) do + { + note: { + date: trip.started_at.to_date - 10.days, + body: 'This should fail' + } + } + end + + it 'does not create the note' do + expect do + post trip_notes_url(trip), params: invalid_params + end.not_to change(Note, :count) + end + end + + context 'when not authenticated' do + before { sign_out user } + + it 'redirects to sign in' do + post trip_notes_url(trip), params: valid_params + expect(response).to redirect_to(new_user_session_path) + end + end + + context 'when accessing another user trip' do + let(:other_user) { create(:user) } + let(:other_trip) { create(:trip, user: other_user) } + + it 'returns not found' do + post trip_notes_url(other_trip), params: valid_params + expect(response).to have_http_status(:not_found) + end + end + end + + describe 'PATCH /trips/:trip_id/notes/:id' do + let!(:note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon, body: 'Original note') + end + + let(:update_params) do + { + note: { + body: 'Updated note content' + } + } + end + + context 'with valid parameters' do + it 'updates the note' do + patch trip_note_url(trip, note), params: update_params + note.reload + expect(note.body.to_plain_text).to eq('Updated note content') + end + + it 'redirects to the trip for HTML format' do + patch trip_note_url(trip, note), params: update_params + expect(response).to redirect_to(trip) + end + end + + context 'when accessing another user trip' do + let(:other_user) { create(:user) } + let(:other_trip) { create(:trip, user: other_user) } + let!(:other_note) do + create(:note, user: other_user, attachable: other_trip, + noted_at: other_trip.started_at.to_date.to_datetime.noon, body: 'Other note') + end + + it 'returns not found' do + patch trip_note_url(other_trip, other_note), params: update_params + expect(response).to have_http_status(:not_found) + end + end + end + + describe 'DELETE /trips/:trip_id/notes/:id' do + let!(:note) do + create(:note, user: user, attachable: trip, + noted_at: trip.started_at.to_date.to_datetime.noon, body: 'Note to delete') + end + + it 'destroys the note' do + expect do + delete trip_note_url(trip, note) + end.to change(Note, :count).by(-1) + end + + it 'redirects to the trip for HTML format' do + delete trip_note_url(trip, note) + expect(response).to redirect_to(trip) + end + + context 'when accessing another user trip' do + let(:other_user) { create(:user) } + let(:other_trip) { create(:trip, user: other_user) } + let!(:other_note) do + create(:note, user: other_user, attachable: other_trip, + noted_at: other_trip.started_at.to_date.to_datetime.noon, body: 'Other note') + end + + it 'returns not found' do + expect do + delete trip_note_url(other_trip, other_note) + end.not_to change(Note, :count) + + expect(response).to have_http_status(:not_found) + end + end + end +end diff --git a/spec/requests/trips_spec.rb b/spec/requests/trips_spec.rb index 15d62338d..7351fd059 100644 --- a/spec/requests/trips_spec.rb +++ b/spec/requests/trips_spec.rb @@ -134,7 +134,7 @@ let(:new_attributes) do { name: 'Updated Trip Name', - notes: 'Changed trip notes' + description: 'Changed trip notes' } end let(:trip) { create(:trip, :with_points, user:) } @@ -144,8 +144,8 @@ trip.reload expect(trip.name).to eq('Updated Trip Name') - expect(trip.notes.body.to_plain_text).to eq('Changed trip notes') - expect(trip.notes).to be_an(ActionText::RichText) + expect(trip.description.body.to_plain_text).to eq('Changed trip notes') + expect(trip.description).to be_an(ActionText::RichText) end it 'redirects to the trip' do diff --git a/spec/swagger/api/v1/notes_controller_spec.rb b/spec/swagger/api/v1/notes_controller_spec.rb new file mode 100644 index 000000000..86f57a094 --- /dev/null +++ b/spec/swagger/api/v1/notes_controller_spec.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true + +require 'swagger_helper' + +describe 'Notes API', type: :request do + let(:user) { create(:user) } + let(:api_key) { user.api_key } + + path '/api/v1/notes' do + get 'List notes' do + tags 'Notes' + produces 'application/json' + parameter name: :Authorization, in: :header, type: :string, required: true, description: 'Bearer token' + parameter name: :attachable_type, in: :query, type: :string, required: false, + description: 'Filter by attachable type (e.g. Trip)' + parameter name: :attachable_id, in: :query, type: :integer, required: false, + description: 'Filter by attachable ID' + parameter name: :standalone, in: :query, type: :string, required: false, + description: 'Set to "true" to return only standalone notes' + + response '200', 'notes found' do + let(:Authorization) { "Bearer #{api_key}" } + + schema type: :array, + items: { + type: :object, + properties: { + id: { type: :integer }, + title: { type: :string, nullable: true }, + body: { type: :string, nullable: true }, + latitude: { type: :number, nullable: true }, + longitude: { type: :number, nullable: true }, + attachable_type: { type: :string, nullable: true }, + attachable_id: { type: :integer, nullable: true }, + date: { type: :string, nullable: true, format: :date }, + noted_at: { type: :string, format: :datetime }, + created_at: { type: :string, format: :datetime }, + updated_at: { type: :string, format: :datetime } + }, + required: %w[id noted_at] + } + + run_test! + end + + response '401', 'unauthorized' do + let(:Authorization) { 'Bearer invalid-token' } + run_test! + end + end + + post 'Create note' do + tags 'Notes' + consumes 'application/json' + produces 'application/json' + parameter name: :Authorization, in: :header, type: :string, required: true, description: 'Bearer token' + parameter name: :note, in: :body, schema: { + type: :object, + properties: { + note: { + type: :object, + properties: { + title: { type: :string }, + body: { type: :string }, + latitude: { type: :number }, + longitude: { type: :number }, + attachable_type: { type: :string }, + attachable_id: { type: :integer }, + noted_at: { type: :string, format: :datetime } + }, + required: %w[noted_at] + } + } + } + + response '201', 'note created' do + let(:Authorization) { "Bearer #{api_key}" } + let(:note) do + { note: { body: 'A test note', noted_at: Time.current.iso8601 } } + end + + schema type: :object, + properties: { + id: { type: :integer }, + title: { type: :string, nullable: true }, + body: { type: :string, nullable: true }, + latitude: { type: :number, nullable: true }, + longitude: { type: :number, nullable: true }, + attachable_type: { type: :string, nullable: true }, + attachable_id: { type: :integer, nullable: true }, + date: { type: :string, nullable: true, format: :date }, + noted_at: { type: :string, format: :datetime }, + created_at: { type: :string, format: :datetime }, + updated_at: { type: :string, format: :datetime } + } + + run_test! + end + + response '422', 'invalid request' do + let(:Authorization) { "Bearer #{api_key}" } + let(:note) { { note: { body: 'No date' } } } + + run_test! + end + + response '401', 'unauthorized' do + let(:Authorization) { 'Bearer invalid-token' } + let(:note) do + { note: { body: 'A test note', noted_at: Time.current.iso8601 } } + end + + run_test! + end + end + end + + path '/api/v1/notes/{id}' do + get 'Show note' do + tags 'Notes' + produces 'application/json' + parameter name: :id, in: :path, type: :integer, required: true, description: 'Note ID' + parameter name: :Authorization, in: :header, type: :string, required: true, description: 'Bearer token' + + response '200', 'note found' do + let(:Authorization) { "Bearer #{api_key}" } + let(:test_note) { create(:note, user: user, noted_at: Time.current) } + let(:id) { test_note.id } + + schema type: :object, + properties: { + id: { type: :integer }, + title: { type: :string, nullable: true }, + body: { type: :string, nullable: true }, + latitude: { type: :number, nullable: true }, + longitude: { type: :number, nullable: true }, + attachable_type: { type: :string, nullable: true }, + attachable_id: { type: :integer, nullable: true }, + date: { type: :string, nullable: true, format: :date }, + noted_at: { type: :string, format: :datetime }, + created_at: { type: :string, format: :datetime }, + updated_at: { type: :string, format: :datetime } + } + + run_test! + end + + response '404', 'note not found' do + let(:Authorization) { "Bearer #{api_key}" } + let(:id) { 999_999 } + + run_test! + end + + response '401', 'unauthorized' do + let(:Authorization) { 'Bearer invalid-token' } + let(:test_note) { create(:note, user: user, noted_at: Time.current) } + let(:id) { test_note.id } + + run_test! + end + end + + patch 'Update note' do + tags 'Notes' + consumes 'application/json' + produces 'application/json' + parameter name: :id, in: :path, type: :integer, required: true, description: 'Note ID' + parameter name: :Authorization, in: :header, type: :string, required: true, description: 'Bearer token' + parameter name: :note, in: :body, schema: { + type: :object, + properties: { + note: { + type: :object, + properties: { + title: { type: :string }, + body: { type: :string }, + latitude: { type: :number }, + longitude: { type: :number }, + noted_at: { type: :string, format: :datetime } + } + } + } + } + + response '200', 'note updated' do + let(:Authorization) { "Bearer #{api_key}" } + let(:test_note) { create(:note, user: user, noted_at: Time.current) } + let(:id) { test_note.id } + let(:note) { { note: { body: 'Updated note' } } } + + schema type: :object, + properties: { + id: { type: :integer }, + title: { type: :string, nullable: true }, + body: { type: :string, nullable: true }, + latitude: { type: :number, nullable: true }, + longitude: { type: :number, nullable: true }, + attachable_type: { type: :string, nullable: true }, + attachable_id: { type: :integer, nullable: true }, + date: { type: :string, nullable: true, format: :date }, + noted_at: { type: :string, format: :datetime }, + created_at: { type: :string, format: :datetime }, + updated_at: { type: :string, format: :datetime } + } + + run_test! + end + + response '404', 'note not found' do + let(:Authorization) { "Bearer #{api_key}" } + let(:id) { 999_999 } + let(:note) { { note: { body: 'Updated note' } } } + + run_test! + end + + response '401', 'unauthorized' do + let(:Authorization) { 'Bearer invalid-token' } + let(:test_note) { create(:note, user: user, noted_at: Time.current) } + let(:id) { test_note.id } + let(:note) { { note: { body: 'Updated note' } } } + + run_test! + end + end + + delete 'Delete note' do + tags 'Notes' + parameter name: :id, in: :path, type: :integer, required: true, description: 'Note ID' + parameter name: :Authorization, in: :header, type: :string, required: true, description: 'Bearer token' + + response '200', 'note deleted' do + let(:Authorization) { "Bearer #{api_key}" } + let(:test_note) { create(:note, user: user, noted_at: Time.current) } + let(:id) { test_note.id } + + run_test! + end + + response '404', 'note not found' do + let(:Authorization) { "Bearer #{api_key}" } + let(:id) { 999_999 } + + run_test! + end + + response '401', 'unauthorized' do + let(:Authorization) { 'Bearer invalid-token' } + let(:test_note) { create(:note, user: user, noted_at: Time.current) } + let(:id) { test_note.id } + + run_test! + end + end + end +end diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index a16602d63..7475a7610 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -252,6 +252,335 @@ paths: properties: status: type: string + "/api/v1/notes": + get: + summary: List notes + tags: + - Notes + parameters: + - name: Authorization + in: header + required: true + description: Bearer token + schema: + type: string + - name: attachable_type + in: query + required: false + description: Filter by attachable type (e.g. Trip) + schema: + type: string + - name: attachable_id + in: query + required: false + description: Filter by attachable ID + schema: + type: integer + - name: standalone + in: query + required: false + description: Set to "true" to return only standalone notes + schema: + type: string + responses: + '200': + description: notes found + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + title: + type: string + nullable: true + body: + type: string + nullable: true + latitude: + type: number + nullable: true + longitude: + type: number + nullable: true + attachable_type: + type: string + nullable: true + attachable_id: + type: integer + nullable: true + date: + type: string + nullable: true + format: date + noted_at: + type: string + format: datetime + created_at: + type: string + format: datetime + updated_at: + type: string + format: datetime + required: + - id + - noted_at + '401': + description: unauthorized + post: + summary: Create note + tags: + - Notes + parameters: + - name: Authorization + in: header + required: true + description: Bearer token + schema: + type: string + responses: + '201': + description: note created + content: + application/json: + schema: + type: object + properties: + id: + type: integer + title: + type: string + nullable: true + body: + type: string + nullable: true + latitude: + type: number + nullable: true + longitude: + type: number + nullable: true + attachable_type: + type: string + nullable: true + attachable_id: + type: integer + nullable: true + date: + type: string + nullable: true + format: date + noted_at: + type: string + format: datetime + created_at: + type: string + format: datetime + updated_at: + type: string + format: datetime + '422': + description: invalid request + '401': + description: unauthorized + requestBody: + content: + application/json: + schema: + type: object + properties: + note: + type: object + properties: + title: + type: string + body: + type: string + latitude: + type: number + longitude: + type: number + attachable_type: + type: string + attachable_id: + type: integer + noted_at: + type: string + format: datetime + required: + - noted_at + "/api/v1/notes/{id}": + get: + summary: Show note + tags: + - Notes + parameters: + - name: id + in: path + required: true + description: Note ID + schema: + type: integer + - name: Authorization + in: header + required: true + description: Bearer token + schema: + type: string + responses: + '200': + description: note found + content: + application/json: + schema: + type: object + properties: + id: + type: integer + title: + type: string + nullable: true + body: + type: string + nullable: true + latitude: + type: number + nullable: true + longitude: + type: number + nullable: true + attachable_type: + type: string + nullable: true + attachable_id: + type: integer + nullable: true + date: + type: string + nullable: true + format: date + noted_at: + type: string + format: datetime + created_at: + type: string + format: datetime + updated_at: + type: string + format: datetime + '404': + description: note not found + '401': + description: unauthorized + patch: + summary: Update note + tags: + - Notes + parameters: + - name: id + in: path + required: true + description: Note ID + schema: + type: integer + - name: Authorization + in: header + required: true + description: Bearer token + schema: + type: string + responses: + '200': + description: note updated + content: + application/json: + schema: + type: object + properties: + id: + type: integer + title: + type: string + nullable: true + body: + type: string + nullable: true + latitude: + type: number + nullable: true + longitude: + type: number + nullable: true + attachable_type: + type: string + nullable: true + attachable_id: + type: integer + nullable: true + date: + type: string + nullable: true + format: date + noted_at: + type: string + format: datetime + created_at: + type: string + format: datetime + updated_at: + type: string + format: datetime + '404': + description: note not found + '401': + description: unauthorized + requestBody: + content: + application/json: + schema: + type: object + properties: + note: + type: object + properties: + title: + type: string + body: + type: string + latitude: + type: number + longitude: + type: number + noted_at: + type: string + format: datetime + delete: + summary: Delete note + tags: + - Notes + parameters: + - name: id + in: path + required: true + description: Note ID + schema: + type: integer + - name: Authorization + in: header + required: true + description: Bearer token + schema: + type: string + responses: + '200': + description: note deleted + '404': + description: note not found + '401': + description: unauthorized "/api/v1/overland/batches": post: summary: Creates a batch of points