@charset "UTF-8";

/* ═══════════════════════════════════════════════════════════════════
   Unimarket — the design system the app uses, for the website.

   The site had 9,478 lines of CSS living inside 92 PHP pages: tokens
   copy-pasted where they existed at all, every button and field
   hand-rolled per page, no shared layout. That is precisely where the
   Flutter app was before its rewrite, and the fix is the same one —
   one set of tokens, one set of components, and pages that compose them
   instead of re-inventing them.

   Names mirror the app's `lib/src/core/theme` and `core/widgets` so a
   change in one has an obvious counterpart in the other:

     AppColors      → the :root block
     AppSpacing     → --space-*, --r-*
     MarketButton   → .um-btn
     MarketTextField→ .um-field
     MarketSurface  → .um-card
     MarketEmptyState → .um-empty
     MarketShimmer  → .um-skeleton

   Values are taken from the app, including the three that were darkened
   there for WCAG contrast and never made it back to the site: muted,
   moss and amber.
   ═══════════════════════════════════════════════════════════════════ */

:root {
    /* Brand — deep greens, from darkest surface to the accent. */
    --ink:        #0C1810;
    --forest:     #0F3825;
    --grove:      #1A5C3A;
    --canopy:     #237A4B;
    --moss:       #35A065;   /* was #3DAD6E — failed contrast on warm-white */
    --lime:       #A8E63D;
    --lime-dim:   rgba(168, 230, 61, 0.14);

    /* Surfaces, lightest to heaviest. */
    --cream:      #F7F5F0;
    --warm-white: #FDFCFA;
    --parchment:  #EEE9E0;
    --sand:       #D6CFC2;

    /* Text and state. */
    --muted:      #63706A;   /* was #7A8780 — failed contrast on cream */
    --alert:      #E5352A;
    --amber:      #C2740A;   /* was #F59E0B — failed contrast as text */

    /* Foreground pairs. `--on-brand` is what goes on top of --grove. */
    --brand-on-surface: #0F3825;
    --on-brand:         #FFFFFF;

    /* Type. */
    --font-display: 'Bricolage Grotesque', system-ui, sans-serif;
    --font-body:    'DM Sans', system-ui, -apple-system, sans-serif;

    /* Spacing — AppSpacing, one to one. */
    --space-4: 4px;  --space-8: 8px;   --space-12: 12px;
    --space-16: 16px; --space-24: 24px; --space-32: 32px; --space-48: 48px;

    /* Radius — AppRadius, one to one. */
    --r-xs: 8px; --r-sm: 12px; --r-md: 16px; --r-lg: 22px; --r-full: 999px;

    --s1: 0 1px 2px rgba(12, 24, 16, .05);
    --s2: 0 2px 8px rgba(12, 24, 16, .08), 0 1px 3px rgba(12, 24, 16, .05);
    --s3: 0 8px 28px rgba(12, 24, 16, .11), 0 2px 8px rgba(12, 24, 16, .06);

    --header-h: 62px;
    --nav-h: 58px;
}

/* The app has a dark theme, so the site does too. Only pages using this
   stylesheet follow it; the ones still on their own inline CSS stay
   light until they are migrated. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --ink:        #F2F5F0;
        --forest:     #0A1F14;
        --grove:      #3DAD6E;
        --canopy:     #4FC183;
        --moss:       #6FD49E;
        --lime:       #B9F05C;
        --cream:      #0B120E;
        --warm-white: #141C17;
        --parchment:  #1F2A23;
        --sand:       #2C382F;
        --muted:      #93A199;
        --alert:      #FF6B5F;
        --amber:      #FFC04D;
        --brand-on-surface: #6FD49E;
        --on-brand:   #07160E;
        --s1: 0 1px 2px rgba(0, 0, 0, .4);
        --s2: 0 2px 8px rgba(0, 0, 0, .45);
        --s3: 0 8px 28px rgba(0, 0, 0, .5);
    }
}

/* ─── Base ─────────────────────────────────────────────────────── */

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
    font-family: var(--font-body);
    background: var(--cream);
    color: var(--ink);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; }

/* Anything that can be tabbed to says so. The site had no visible focus
   ring at all, which makes keyboard use guesswork. */
:focus-visible {
    outline: 2px solid var(--canopy);
    outline-offset: 2px;
    border-radius: var(--r-xs);
}

/* ─── Type scale — AppTypography ───────────────────────────────── */

.um-display  { font-family: var(--font-display); font-size: 2.125rem; font-weight: 800; letter-spacing: -1px;   line-height: 1.05; }
.um-h1       { font-family: var(--font-display); font-size: 1.75rem;  font-weight: 800; letter-spacing: -.8px;  line-height: 1.1; }
.um-h2       { font-family: var(--font-display); font-size: 1.5rem;   font-weight: 800; letter-spacing: -.6px; }
.um-h3       { font-family: var(--font-display); font-size: 1.3125rem;font-weight: 800; letter-spacing: -.5px; }
.um-h4       { font-family: var(--font-display); font-size: 1.1875rem;font-weight: 700; letter-spacing: -.4px; }
.um-title    { font-size: 1.03rem;  font-weight: 700; letter-spacing: -.3px; }
.um-body     { font-size: .95rem;   font-weight: 500; line-height: 1.45; }
.um-body-sm  { font-size: .86rem;   font-weight: 500; }
.um-label    { font-size: .8rem;    font-weight: 700; }
.um-muted    { color: var(--muted); }
.um-price    { color: var(--grove); font-weight: 700; }

/* ─── Layout ───────────────────────────────────────────────────── */

.um-page { max-width: 960px; margin: 0 auto; padding: var(--space-16); }
.um-page--narrow { max-width: 620px; }
/* Clear of the fixed bottom nav and any action bar. */
.um-page--has-nav { padding-bottom: calc(var(--nav-h) + var(--space-32)); }

.um-stack   { display: flex; flex-direction: column; gap: var(--space-16); }
.um-row     { display: flex; align-items: center; gap: var(--space-12); }
.um-row--tight { gap: var(--space-8); }
.um-spacer  { flex: 1; }

.um-section-title {
    font-family: var(--font-display);
    font-size: 1.05rem; font-weight: 700;
    margin-bottom: var(--space-12);
}

/* ─── Header ───────────────────────────────────────────────────── */

.um-header {
    position: sticky; top: 0; z-index: 40;
    min-height: var(--header-h);
    display: flex; align-items: center; gap: var(--space-12);
    padding: 0 var(--space-16);
    background: var(--warm-white);
    border-bottom: 1px solid var(--parchment);
}
.um-header__back {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; margin-left: -8px;
    border-radius: var(--r-full); text-decoration: none;
    color: var(--ink); font-size: 1.05rem;
}
.um-header__back:hover { background: var(--parchment); }
.um-header__title {
    font-family: var(--font-display); font-size: 1.05rem; font-weight: 600;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.um-header__actions { margin-left: auto; display: flex; gap: var(--space-8); }

/* ─── Buttons — MarketButton ───────────────────────────────────── */

.um-btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--space-8);
    padding: 13px var(--space-24);
    border: none; border-radius: var(--r-full);
    font-family: var(--font-body); font-size: .95rem; font-weight: 700;
    text-decoration: none; cursor: pointer;
    transition: transform .12s ease, filter .12s ease, background .12s ease;
    /* Never smaller than a thumb. */
    min-height: 46px;
}
.um-btn:active { transform: scale(.985); }
.um-btn:disabled, .um-btn[aria-disabled="true"] {
    opacity: .5; cursor: not-allowed; transform: none;
}
.um-btn--block { width: 100%; }

.um-btn--primary   { background: var(--grove); color: var(--on-brand); }
.um-btn--primary:hover:not(:disabled) { filter: brightness(1.08); }
.um-btn--secondary { background: color-mix(in srgb, var(--grove) 10%, transparent); color: var(--grove); }
.um-btn--tertiary  { background: transparent; color: var(--grove); }
.um-btn--tertiary:hover { background: var(--parchment); }
.um-btn--destructive { background: var(--alert); color: #fff; }
.um-btn--outline   { background: transparent; color: var(--grove); border: 1.5px solid var(--grove); }

/* The in-button spinner. Content the page is fetching gets a skeleton;
   a button you just pressed gets this, because the two mean different
   things — see market_skeleton.dart. */
.um-btn.is-loading { color: transparent !important; pointer-events: none; position: relative; }
.um-btn.is-loading::after {
    content: ""; position: absolute;
    width: 18px; height: 18px;
    border: 2px solid currentColor; border-top-color: transparent;
    border-radius: 50%;
    animation: um-spin .7s linear infinite;
    color: var(--on-brand);
}
.um-btn--secondary.is-loading::after,
.um-btn--outline.is-loading::after,
.um-btn--tertiary.is-loading::after { color: var(--grove); }
@keyframes um-spin { to { transform: rotate(360deg); } }

/* ─── Fields — MarketTextField ─────────────────────────────────── */

.um-field { display: block; margin-bottom: var(--space-16); }
.um-field__label {
    display: block; margin-bottom: var(--space-8);
    font-size: .78rem; font-weight: 700; letter-spacing: .5px;
    text-transform: uppercase; color: var(--muted);
}
.um-field__hint { margin-top: var(--space-4); font-size: .78rem; color: var(--muted); }
.um-field__error { margin-top: var(--space-4); font-size: .8rem; color: var(--alert); font-weight: 500; }

.um-input, .um-select, .um-textarea {
    width: 100%;
    padding: 13px var(--space-16);
    font-family: var(--font-body); font-size: .95rem; color: var(--ink);
    background: var(--warm-white);
    border: 1.5px solid var(--parchment);
    border-radius: var(--r-sm);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.um-textarea { min-height: 110px; resize: vertical; line-height: 1.5; }
.um-input:focus, .um-select:focus, .um-textarea:focus {
    outline: none;
    border-color: var(--canopy);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--canopy) 15%, transparent);
}
.um-input::placeholder, .um-textarea::placeholder { color: var(--muted); opacity: .75; }
.um-field--invalid .um-input,
.um-field--invalid .um-select,
.um-field--invalid .um-textarea { border-color: var(--alert); }

.um-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2363706A' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    background-size: 18px;
    padding-right: 42px;
}

.um-search {
    width: 100%;
    padding: 12px var(--space-16) 12px 42px;
    font-family: var(--font-body); font-size: .95rem;
    background: var(--warm-white) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2363706A' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3'/%3E%3C/svg%3E") no-repeat 14px center / 18px;
    border: 1.5px solid var(--parchment);
    border-radius: var(--r-full);
    color: var(--ink);
}
.um-search:focus { outline: none; border-color: var(--canopy); }

.um-check { display: inline-flex; align-items: center; gap: var(--space-8); cursor: pointer; font-size: .9rem; }
.um-check input { width: 17px; height: 17px; accent-color: var(--canopy); }

/* ─── Surfaces — MarketSurface ─────────────────────────────────── */

.um-card {
    background: var(--warm-white);
    border: 1px solid var(--parchment);
    border-radius: var(--r-md);
    padding: var(--space-16);
    box-shadow: var(--s2);
}
.um-card--flat { box-shadow: none; }
.um-card--tap { text-decoration: none; color: inherit; display: block; transition: transform .12s ease, box-shadow .12s ease; }
.um-card--tap:hover { transform: translateY(-2px); box-shadow: var(--s3); }

/* A row of photos you swipe, not a slideshow you wait for. Snap points
   so a half-scrolled photo settles, and the scrollbar hidden because on
   a phone it is only ever noise. */
.um-gallery {
    display: flex; gap: 2px;
    overflow-x: auto; scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.um-gallery::-webkit-scrollbar { display: none; }
.um-gallery__item {
    flex: 0 0 100%; scroll-snap-align: center;
    aspect-ratio: 16 / 10; background: var(--parchment);
}
.um-gallery__item img { width: 100%; height: 100%; object-fit: cover; }
/* More than one photo: show a sliver of the next, so it is obvious there
   is one to swipe to. */
.um-gallery__item:not(:only-child) { flex-basis: 92%; }

/* ─── The housing terms gate ───────────────────────────────────── */

.um-terms {
    position: fixed; inset: 0; z-index: 10000;
    display: flex; align-items: flex-end; justify-content: center;
    background: rgba(12, 24, 16, .55);
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
/* An author `display:flex` outranks the browser's own [hidden] rule, so
   without this the gate never closes — the button works, the panel just
   stays on screen. */
.um-terms[hidden] { display: none; }
@media (min-width: 640px) { .um-terms { align-items: center; padding: var(--space-24); } }

.um-terms__panel {
    background: var(--warm-white);
    width: 100%; max-width: 560px;
    max-height: 88vh;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    display: flex; flex-direction: column;
    box-shadow: var(--s3);
    animation: um-sheet-up .26s ease-out;
}
@media (min-width: 640px) { .um-terms__panel { border-radius: var(--r-lg); } }
@keyframes um-sheet-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) { .um-terms__panel { animation: none; } }

.um-terms__head { padding: var(--space-16) var(--space-16) var(--space-12); border-bottom: 1px solid var(--parchment); }
.um-terms__foot { padding: var(--space-12) var(--space-16); border-top: 1px solid var(--parchment); }
.um-terms__body {
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    padding: var(--space-16);
    font-size: .9rem; line-height: 1.55; color: var(--ink);
}
.um-terms__body h3 {
    font-family: var(--font-display); font-size: .95rem; font-weight: 700;
    margin: var(--space-16) 0 4px;
}
.um-terms__body h3:first-child { margin-top: 0; }
.um-terms__body p { margin-bottom: var(--space-8); color: var(--muted); }
.um-terms__body strong { color: var(--ink); font-weight: 700; }

/* A settings-style list of rows inside a card — the app's MarketListTile.
   Profile, settings, hostel facts and shop details are all this shape. */
.um-list { padding: 0; overflow: hidden; }
.um-list__row {
    display: flex; align-items: center; gap: var(--space-12);
    padding: 14px var(--space-16);
    text-decoration: none; color: inherit;
    border-bottom: 1px solid var(--parchment);
}
.um-list__row:last-child { border-bottom: 0; }
a.um-list__row:hover { background: var(--parchment); }
.um-list__row i:first-child { width: 20px; text-align: center; color: var(--canopy); }
.um-list__row .um-list__meta { color: var(--muted); font-size: .85rem; }
.um-list__row .um-list__chev { font-size: .75rem; color: var(--muted); }

.um-pill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 11px;
    background: var(--parchment);
    border-radius: var(--r-full);
    font-size: .78rem; color: var(--brand-on-surface); white-space: nowrap;
}
.um-pill i, .um-pill svg { font-size: .72rem; color: var(--canopy); }
.um-pill--brand  { background: var(--grove); color: var(--on-brand); }
.um-pill--alert  { background: color-mix(in srgb, var(--alert) 12%, transparent); color: var(--alert); font-weight: 700; }
.um-pill--amber  { background: color-mix(in srgb, var(--amber) 14%, transparent); color: var(--amber); font-weight: 700; }
.um-pill--moss   { background: color-mix(in srgb, var(--moss) 14%, transparent); color: var(--grove); font-weight: 700; }
.um-pill-row { display: flex; flex-wrap: wrap; gap: var(--space-8); }

/* Chips that filter. Selected reads as chosen, not merely hovered. */
.um-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 14px;
    background: var(--warm-white);
    border: 1.5px solid var(--parchment);
    border-radius: var(--r-full);
    font-size: .85rem; color: var(--ink);
    text-decoration: none; cursor: pointer; white-space: nowrap;
}
.um-chip:hover { border-color: var(--sand); }
.um-chip.is-selected { background: var(--grove); border-color: var(--grove); color: var(--on-brand); font-weight: 700; }

/* ─── Grids ────────────────────────────────────────────────────── */

.um-grid { display: grid; gap: var(--space-16); }
.um-grid--cards { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.um-grid--wide  { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
@media (max-width: 520px) {
    .um-grid--cards { grid-template-columns: repeat(2, 1fr); gap: var(--space-12); }
}

/* ─── Media — MarketImage ──────────────────────────────────────── */

.um-media {
    position: relative; overflow: hidden;
    background: var(--parchment);
    display: flex; align-items: center; justify-content: center;
    color: var(--muted);
}
.um-media img { width: 100%; height: 100%; object-fit: cover; }
.um-media--square { aspect-ratio: 1 / 1; }
.um-media--card   { aspect-ratio: 4 / 3; }
.um-media--hero   { aspect-ratio: 16 / 10; }
/* Fills whatever box it is placed in — for a photo the caller has
   already given an aspect ratio, with things layered on top of it. */
.um-media--fill   { position: absolute; inset: 0; }

/* ─── Empty state — MarketEmptyState ───────────────────────────── */

.um-empty {
    display: flex; flex-direction: column; align-items: center;
    text-align: center;
    padding: var(--space-48) var(--space-24);
    gap: var(--space-8);
}
.um-empty__icon {
    width: 74px; height: 74px; margin-bottom: var(--space-8);
    display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--moss) 14%, transparent);
    border-radius: var(--r-full);
    font-size: 1.7rem; color: var(--grove);
}
.um-empty__title { font-family: var(--font-display); font-size: 1.15rem; font-weight: 700; }
.um-empty__msg   { color: var(--muted); font-size: .9rem; max-width: 42ch; }

/* ─── Skeletons — MarketShimmer ────────────────────────────────── */

.um-skeleton { display: block; background: rgba(12, 24, 16, .06); border-radius: var(--r-sm); position: relative; overflow: hidden; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .um-skeleton { background: rgba(255, 255, 255, .07); } }
.um-skeleton::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .45), transparent);
    animation: um-sweep 1.3s ease-in-out infinite;
}
@keyframes um-sweep { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
.um-skeleton--line { height: 12px; border-radius: var(--r-xs); }
.um-skeleton--title { height: 18px; width: 60%; border-radius: var(--r-xs); }

/* Someone who asked the OS to reduce motion should not be handed a
   sweep that loops until the data lands. The shapes still hold the
   layout; they just sit still. */
@media (prefers-reduced-motion: reduce) {
    .um-skeleton::after { animation: none; background: none; }
    .um-btn.is-loading::after { animation-duration: 2s; }
    * { scroll-behavior: auto !important; }
}

/* ─── Notices ──────────────────────────────────────────────────── */

.um-notice {
    display: flex; gap: var(--space-12); align-items: flex-start;
    padding: var(--space-12) var(--space-16);
    border-radius: var(--r-sm);
    font-size: .9rem;
    margin-bottom: var(--space-16);
}
.um-notice--info    { background: color-mix(in srgb, var(--canopy) 10%, transparent); color: var(--brand-on-surface); }
.um-notice--success { background: color-mix(in srgb, var(--moss) 15%, transparent); color: var(--grove); }
.um-notice--warn    { background: color-mix(in srgb, var(--amber) 14%, transparent); color: var(--amber); }
.um-notice--error   { background: color-mix(in srgb, var(--alert) 11%, transparent); color: var(--alert); }

/* ─── Action bar — the app's bottomNavigationBar on a detail page ─ */

.um-action-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    display: flex; gap: var(--space-8);
    padding: var(--space-12) var(--space-16) calc(var(--space-12) + env(safe-area-inset-bottom));
    background: var(--warm-white);
    border-top: 1px solid var(--parchment);
}
.um-action-bar .um-btn { flex: 1; }
.um-action-bar .um-btn--icon { flex: 0 0 auto; width: 46px; padding: 0; }

/* ─── Bottom nav ───────────────────────────────────────────────── */

.um-nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    height: calc(var(--nav-h) + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    display: flex; align-items: stretch;
    background: var(--warm-white);
    border-top: 1px solid var(--parchment);
}
.um-nav__item {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px;
    text-decoration: none; color: var(--muted);
    font-size: .68rem; font-weight: 600;
    position: relative;
}
.um-nav__item svg, .um-nav__item i { font-size: 1.15rem; width: 22px; height: 22px; }
.um-nav__item.is-active { color: var(--grove); }
.um-nav__badge {
    position: absolute; top: 6px; left: 50%; margin-left: 4px;
    min-width: 17px; height: 17px; padding: 0 4px;
    display: flex; align-items: center; justify-content: center;
    background: var(--alert); color: #fff;
    border-radius: var(--r-full);
    font-size: .62rem; font-weight: 800;
}
/* The centre action, like the app's + button. */
.um-nav__fab {
    flex: 0 0 auto; width: 54px;
    display: flex; align-items: center; justify-content: center;
    align-self: center;
    height: 46px; margin: 0 var(--space-8);
    background: var(--grove); color: var(--on-brand);
    border-radius: var(--r-full);
    text-decoration: none; font-size: 1.2rem;
    box-shadow: var(--s2);
}

.um-sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* A horizontal scroller. Lived inline in index.php until
   unimarket_download.php needed one for its screenshots; index.php keeps
   its own copy of these exact rules, which override with the same values
   rather than conflicting. */
.rail { display: flex; gap: var(--space-12); overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: var(--space-8); -webkit-overflow-scrolling: touch; }
.rail::-webkit-scrollbar { display: none; }
.rail > * { scroll-snap-align: start; flex: 0 0 auto; }
