/* ============================================================
   App shell redesign — re-themes the logged-in experience (listings,
   listing detail, my listings, new/edit listing, saved homes, messaging,
   roommates) to match the cream / Cormorant Garamond + Inter / olive
   brand established on the landing page and auth pages.

   How this works: static/css/styles.css already routes almost every
   rule through CSS custom properties (--forest, --lime, --mint, --fd,
   --fb, --border, --sh-sm, --r-lg, …) instead of hardcoded values —
   including inline style="...var(--forest)..." attributes baked into
   the templates. Redefining those properties once, scoped under
   .app-redesign (the new body class), re-themes the entire shell —
   sidebar, cards, buttons, badges, chat bubbles, forms — without
   touching a single template. Only the handful of truly hardcoded
   values (#fff, literal hex) below need a direct selector override.
   ============================================================ */

.app-redesign{
  --white:#f8f6ef; --bg:#f2eee5; --surface:#f8f6ef; --surface-alt:#ede8dd;
  --mint:#ede8dd; --mint-soft:#f2eee5;
  --lime:#8e9c75; --lime-dark:#7c8a64;
  /* The brand guideline's signal green, promoted here from campus_picker.css
     so the shell can use it too. It is the one vivid colour in the palette
     and it is for interactive moments only — a chosen card, a focus ring, the
     active quick filter — never a surface. Same value and same rule as the
     picker's local pair; that file keeps its own because it also renders
     under .plain-redesign, which never loads these tokens. */
  --lime-pop:#b5e02f; --lime-pop-deep:#9ac41f;
  --forest:#1c2016; --forest-800:#12140f; --forest-600:#2a3322;
  --green:#7c8a64;
  --text:#171512; --text-2:rgba(23,21,18,.62); --text-3:rgba(23,21,18,.42);
  --on-dark:#f2eee5; --on-dark-2:rgba(242,238,229,.62); --on-lime:#171512;
  --border:rgba(23,21,18,.08); --border-2:rgba(23,21,18,.16);
  /* Older names for the two above, kept as aliases rather than renamed.
     templates/tours/_style.html was written against these, and an undefined
     custom property does not quietly fall back — it makes the whole
     declaration invalid at computed-value time, so every
     `border:1px solid var(--line)` on the tour pages rendered no border at
     all. Two names for one colour is a small price; a card with no edge,
     traced back through a missing variable, is not. */
  --line:var(--border); --ink-soft:var(--text-2);
  --danger:#b3543f; --warning:#a8702f; --star:#c9a227;
  --r-sm:10px; --r-md:14px; --r-lg:22px; --r-xl:28px; --pill:999px;
  --sh-sm:0 4px 14px rgba(23,21,18,.07);
  --sh:0 14px 34px rgba(23,21,18,.10);
  --sh-lg:0 30px 70px rgba(23,21,18,.16);
  --fd:'Inter',system-ui,sans-serif;
  --fb:'Inter',system-ui,sans-serif;
}

/* ---------- Display type — Cormorant Garamond for headings, prices,
   stat values and the sidebar wordmark; everything else (buttons,
   nav, badges, card titles) stays Inter, matching the landing page. ---------- */
.app-redesign h1,
.app-redesign h2,
.app-redesign h3,
.app-redesign h4{
  font-family:'Cormorant Garamond', serif; font-weight:500; letter-spacing:-.01em;
}
.app-redesign .logo .wm{ font-family:'Cormorant Garamond', serif; font-weight:500; font-size:21px; }
.app-redesign .prop-card .price{ font-family:'Cormorant Garamond', serif; font-weight:600; font-size:17px; }
.app-redesign .stat .v{ font-family:'Cormorant Garamond', serif; font-weight:500; }

/* ---------- Buttons: one filled style (ink/cream), matching the
   landing page — there is no separate "lime" primary button in this
   brand, so .btn-primary and .btn-dark render identically. ---------- */
.app-redesign .btn-primary{ background:var(--forest); color:var(--on-dark); }
.app-redesign .btn-primary:hover{ background:#2a2621; }
.app-redesign .btn{ font-weight:500; }

/* ---------- Hardcoded (non-variable) colors in styles.css that need
   a direct override to pick up the cream theme. ---------- */
.app-redesign .topbar{ background:var(--white); border-bottom:1px solid var(--border); }
.app-redesign .msg .list{ background:var(--white); }
.app-redesign .bubble.them{ background:var(--white); border-color:var(--border); }
.app-redesign .prop-card .fav{ background:var(--white); }
.app-redesign .badge-warn{ background:#f3e6da; color:var(--warning); }
.app-redesign .drawer-backdrop{ background:rgba(23,21,18,.5); }
.app-redesign .sidebar.open{ box-shadow:0 0 60px rgba(23,21,18,.4); }

/* ---------- Sidebar polish — subtle depth to match the dark ink
   panels used elsewhere in the brand (auth page, pricing card). ---------- */
.app-redesign .sidebar{
  /* Deepened for the logo, and only for the logo.

     The mark's own body is #242e1b. Against the old #202519 the two were ten
     points apart in luminance and the same dark olive in hue, so the D simply
     dissolved into the panel behind it — the lime roof and the window floated
     with no shape around them. At #0d1a10 the body reads as a distinct green
     against a near-black ground, and the extrusion along its right edge has
     something to sit against.

     Only the sidebar moves. --forest stays where it is, because it is the
     fill for every primary button and bubble in the app and those are all
     seen against light backgrounds. */
  background:linear-gradient(165deg, #0d1a10 0%, #050d07 100%);
}
.app-redesign .sidebar .logo .mk{ width:50px; height:50px; }
.app-redesign .sidebar .snav a{ transition:background .15s ease, color .15s ease; }

/* ---------- Verified badge + focus ring accent ---------- */
.app-redesign :focus-visible{ outline:2px solid var(--lime); outline-offset:2px; }

/* ---------- Fields that explain themselves (partials/formfields_explained.html).

   A question mark beside the label that opens the explanation. It exists
   because a field named "Is discoverable" is a database column with a
   checkbox, and the only thing a student can do with it is guess.

   The panel is laid out in the flow, not floated over the form. The first
   version of this absolutely positioned the panel under the question mark,
   which looked right on a laptop and hung 69px off the left edge of a 390px
   phone — the explanation would have been half off-screen on the device most
   students are holding. `display:contents` on the <details> lets the summary
   sit beside the label while the panel, given a full row of its own, pushes
   the rest of the form down instead of covering it. Nothing can be clipped
   because nothing is out of the flow. ---------- */
.app-redesign .fld-head{
  display:grid; grid-template-columns:auto 1fr;
  align-items:center; column-gap:8px; row-gap:6px;
}
.app-redesign .fld-head label{ margin:0; grid-column:1; }
/* A yes/no field reads as a sentence with a box in front of it, which is how
   the sign-in and signup pages already draw theirs. Without this the box sits
   on its own line under the words, so the label looks like a heading for
   whatever comes next rather than the thing the box answers. */
.app-redesign .form .fld:has(> input[type=checkbox]){
  flex-direction:row; align-items:flex-start; gap:10px;
}
.app-redesign .form .fld:has(> input[type=checkbox]) > input[type=checkbox]{
  order:-1; flex:none; margin:2px 0 0; width:17px; height:17px;
  accent-color:var(--forest); cursor:pointer;
}
.app-redesign .form .fld:has(> input[type=checkbox]) .fld-head{ flex:1 1 auto; align-items:flex-start; }
.app-redesign .form .fld:has(> input[type=checkbox]) .fld-head label{
  font-size:13.5px; font-weight:500; color:var(--ink-85); line-height:1.45;
}
/* The <details> box itself is taken out of the picture, so its summary and its
   panel can be placed by the grid above: the question mark in the column beside
   the label, the panel across both columns underneath. Django's own
   `details:not([open]) > *:not(summary){display:none}` still hides the closed
   panel, because that rule is about the elements, not about the box.

   A grid rather than a wrapping flex row, and that is the whole reason: a flex
   row decides where to break using each item's unshrunk width, so a label long
   enough to fill a phone shoved the question mark onto a line of its own --
   where it read as a stray element rather than as a button belonging to that
   field. A grid column shrinks to fit instead of breaking. */
.app-redesign .why{ display:contents; }
.app-redesign .why > summary{
  list-style:none; cursor:pointer;
  grid-column:2; justify-self:start; align-self:center;
  display:inline-flex; align-items:center; justify-content:center;
  width:17px; height:17px; border-radius:50%;
  border:1px solid var(--border); background:var(--surface-alt);
  color:var(--text-2); font-family:'Inter', sans-serif;
  font-size:10.5px; font-weight:700; line-height:1;
  transition:background .15s ease, color .15s ease, border-color .15s ease;
}
/* Safari and Chrome each draw their own marker on a summary; the circle
   above replaces both. */
.app-redesign .why > summary::-webkit-details-marker{ display:none; }
.app-redesign .why > summary::marker{ content:''; }
.app-redesign .why > summary:hover{ border-color:var(--forest); color:var(--forest); }
.app-redesign .why[open] > summary{
  background:var(--forest); border-color:var(--forest); color:var(--on-dark);
}
.app-redesign .why-body{
  grid-column:1 / -1; box-sizing:border-box;
  padding:11px 13px; border-radius:10px;
  background:var(--forest); color:var(--on-dark);
  font-size:12.5px; font-weight:400; line-height:1.55; letter-spacing:0;
}

/* ---------- Radio / checkbox groups on Django-rendered forms.
   Django 5's default RadioSelect/CheckboxSelectMultiple render each
   option as <div><label><input>…text</label></div>, not <ul><li> —
   targeting "label with an input as its first child" catches that
   pattern regardless of the widget's own class name, while leaving
   single BooleanField checkboxes (label and input as siblings, per
   partials/formfields.html) untouched. ---------- */
.app-redesign .form .fld label:has(> input[type=radio]),
.app-redesign .form .fld label:has(> input[type=checkbox]){
  display:inline-flex; align-items:center; gap:8px; font-weight:500; color:var(--text);
  background:var(--surface-alt); border:1px solid var(--border); padding:9px 13px;
  border-radius:var(--pill); cursor:pointer; margin:4px 6px 0 0;
}
.app-redesign .form .fld label:has(> input[type=radio]:checked),
.app-redesign .form .fld label:has(> input[type=checkbox]:checked){
  background:var(--forest); color:var(--on-dark); border-color:var(--forest);
}

/* ---------- Property card: slightly warmer hover lift, matching the
   landing page's card grad-border feel. ---------- */
.app-redesign .prop-card{ transition:transform .2s ease, box-shadow .2s ease, border-color .2s ease; }
.app-redesign .prop-card:hover{ transform:translateY(-4px); box-shadow:var(--sh); }

/* ---------- Chat bubble: ink instead of near-black forest, unchanged
   shape — just the themed variable, called out here for clarity. ---------- */
.app-redesign .bubble.me{ background:var(--forest); color:var(--on-dark); }

/* ---------- Note / info banner: sage-tinted, matching the landing
   page's note/info card treatment. ---------- */
.app-redesign .note{ background:#eef1e8; color:var(--forest); }
.app-redesign .note .ic{ color:var(--green); }

/* ============================================================
   Listings page — horizontal filter bar + rich property cards.
   Structure and interaction ported from the reference design at
   drentals.ng/listings/ (dark glassmorphism + emerald accent);
   every color below is re-mapped to the cream/ink/olive brand
   instead. Class names kept identical to the reference on purpose.
   ============================================================ */

/* FILTERS BAR — one row of controls, above the grid.

   Two layouts, one intent: the bar is always read as a single horizontal
   line rather than a stack.
   · Wide screens: the controls flex to fill the row. If the row is
     genuinely too narrow for everything, it wraps — but each control and
     the button pair keep their own width, so nothing gets squeezed into a
     two-line "Apply / Filters" again.
   · Phone and small tablet (below the 900px shell breakpoint): the bar
     stops wrapping altogether and becomes a sideways rail — one line of
     controls you swipe, with no visible scrollbar. The rail owns the
     overflow, so the page itself can never scroll sideways. The fading
     edge (driven by .is-scrollable / .fade-* from the listings JS) is the
     cue that more controls are waiting off-screen. */
.app-redesign .filters-section{
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:24px; margin-bottom:32px; box-shadow:var(--sh-sm);
}
.app-redesign .filters-container{
  display:flex; flex-wrap:wrap; gap:18px;
}
.app-redesign .filter-group{
  display:flex; flex-direction:column; gap:8px;
  flex:1 1 180px; min-width:180px;
}
.app-redesign .filter-group label{
  font-family:'Inter', sans-serif; font-size:12.5px; font-weight:600; color:var(--text-2);
  display:flex; align-items:center; gap:6px; white-space:nowrap;
}
.app-redesign .filter-group label .ic{ width:14px; height:14px; color:var(--green); }
.app-redesign .filter-group select,
.app-redesign .filter-group input{
  width:100%; padding:12px 14px; background:var(--surface-alt); border:1px solid var(--border);
  border-radius:var(--r-md); color:var(--text); font-size:14px; font-family:'Inter', sans-serif;
  outline:none; transition:border-color .15s ease, box-shadow .15s ease;
}
.app-redesign .filter-group select:focus,
.app-redesign .filter-group input:focus{ border-color:var(--lime); box-shadow:0 0 0 3px rgba(142,156,117,.2); }
/* flex:0 0 auto — the buttons are a fixed pair that wraps as a unit
   instead of compressing inside a narrow column. margin-left:auto does
   nothing while the pair shares the row (the groups' flex-grow eats the
   free space first), but sends the pair to the right edge on the rare
   narrow-desktop row where it wraps alone. */
.app-redesign .filter-actions{ display:flex; gap:12px; align-items:flex-end; flex:0 0 auto; margin-left:auto; }
.app-redesign .apply-filters{
  padding:12px 24px; background:var(--forest); color:var(--on-dark); border:none;
  border-radius:var(--r-md); font-weight:600; font-family:'Inter', sans-serif; cursor:pointer;
  white-space:nowrap; transition:background .2s ease, transform .15s ease;
}
.app-redesign .apply-filters:hover{ background:#2a2621; transform:translateY(-2px); }
.app-redesign .reset-filters{
  padding:12px 24px; background:var(--surface-alt); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-md); font-weight:600; font-family:'Inter', sans-serif; cursor:pointer;
  text-align:center; white-space:nowrap; transition:background .2s ease;
}
.app-redesign .reset-filters:hover{ background:var(--border-2); }

/* ---- The sideways rail (phone + small tablet) --------------------------
   Below 900px the shell drops its sidebar for a drawer, so the bar has the
   full viewport width, and a wrapping row would strand a control or the
   buttons on a line of their own. Instead: one line, fixed-width controls,
   swipe to see the rest. The padding/negative-margin pair is vertical only:
   it keeps the 3px focus ring on a focused select from being clipped by the
   overflow box, while adding no inline padding — inline padding would offset
   the scroll snap origin and leave the rail permanently scrolled by that
   amount, which in turn would fade the leading edge at rest. */
@media(max-width:899px){
  .app-redesign .filters-container{
    flex-wrap:nowrap; gap:12px; padding:6px 0; margin:-6px 0;
    overflow-x:auto; overflow-y:hidden;
    -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain;
    scroll-snap-type:x proximity;
    scrollbar-width:none; -ms-overflow-style:none;
  }
  .app-redesign .filters-container::-webkit-scrollbar{ width:0; height:0; display:none; }
  /* ~216px keeps the longest price option ("₦300,000 - ₦500,000") legible
     while leaving the next control half-visible as the scroll affordance. */
  .app-redesign .filter-group{
    flex:0 0 auto; min-width:0; width:min(66vw, 216px); scroll-snap-align:start;
  }
  .app-redesign .filter-actions{ scroll-snap-align:end; }
  /* iOS Safari zooms the whole page when a control under 16px takes focus. */
  .app-redesign .filter-group select,
  .app-redesign .filter-group input{ font-size:16px; }
}

/* Rail edge fade — only ever applied while the rail actually overflows,
   and only on the side that still holds controls. */
.app-redesign .filters-container.is-scrollable.fade-end{
  -webkit-mask-image:linear-gradient(to right, #000 0, #000 calc(100% - 40px), transparent 100%);
          mask-image:linear-gradient(to right, #000 0, #000 calc(100% - 40px), transparent 100%);
}
.app-redesign .filters-container.is-scrollable.fade-start{
  -webkit-mask-image:linear-gradient(to right, transparent 0, #000 40px);
          mask-image:linear-gradient(to right, transparent 0, #000 40px);
}
.app-redesign .filters-container.is-scrollable.fade-start.fade-end{
  -webkit-mask-image:linear-gradient(to right, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
          mask-image:linear-gradient(to right, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
}

/* Phone: tighten the card so the rail gets as much width as possible. */
@media(max-width:640px){
  .app-redesign .filters-section{ padding:16px; border-radius:var(--r-md); }
  .app-redesign .filter-actions{ gap:10px; }
  .app-redesign .apply-filters,
  .app-redesign .reset-filters{ padding:12px 20px; }
}

/* ---------- The plain shell — a gate, not a page ------------------------
   Used by the campus picker when it stands in front of signup. Same cream,
   same cards, none of the app: centred in whatever screen it landed on, with
   room to breathe at the edges.

   Vertically centred with an auto margin rather than justify-content, which
   clips the top of anything taller than the viewport — on a phone the eight
   cards always are. */
.plain-redesign .plain-shell{
  min-height:100vh; display:flex; flex-direction:column; background:var(--bg);
}
.plain-redesign .plain-brand{
  display:flex; align-items:center; gap:9px;
  width:100%; max-width:1080px; margin:0 auto; padding:24px 22px 0;
}
.plain-redesign .plain-brand .mk{
  width:40px; height:40px; object-fit:contain; flex:none; display:block;
}
.plain-redesign .plain-brand .wm{
  font-family:'Cormorant Garamond', serif; font-weight:500; font-size:20px; color:var(--forest);
}
.plain-redesign .plain-main{ flex:1; display:flex; flex-direction:column; }
/* margin:auto centres it both ways and, unlike justify-content:center, does
   not push the top out of reach when the content is taller than the screen. */
.plain-redesign .plain-main .content-area{
  width:100%; max-width:1080px; margin:auto; padding:30px 22px 64px;
}

/* ---------- Locked fields ------------------------------------------------
   A value the reader can see and cannot change. A plain disabled input
   already refuses the edit; the dashed border and the lock say so before
   they try, which is the difference between a rule and a puzzle. */
.app-redesign .locked-field{
  width:100%; padding:12px 14px; border-radius:var(--r-md);
  border:1px dashed var(--border-2); background:var(--surface-alt);
  color:var(--text-2); font-family:'Inter', sans-serif; font-size:14px;
  cursor:not-allowed;
}
/* Safari greys a disabled field into illegibility; this is a value to read. */
.app-redesign .locked-field:disabled{ opacity:1; -webkit-text-fill-color:var(--text-2); }
.app-redesign .locked-label .ic{ width:13px; height:13px; color:var(--text-3); vertical-align:-2px; }

/* ---------- Campus access ------------------------------------------------
   Asking for another campus to post to. Laid out as a page rather than a
   form dumped in a column: the campuses are the content, so they get a grid
   that fills the width and collapses on its own as it narrows.

   These were pills once, with border-radius:999px. A pill is a shape for
   something short and fixed — "WiFi", "Verified". Put a three-line university
   name in one and the radius turns it into a circle, which is what it did:
   two of the eight rendered as dark blobs with the text wrapped inside. */
.app-redesign .campus-access{ max-width:1040px; }
.app-redesign .ca-lede{ color:var(--text-2); font-size:15px; margin-bottom:20px; max-width:70ch; }
.app-redesign .ca-h2{
  font-family:'Cormorant Garamond', serif; font-weight:500; font-size:21px;
  color:var(--forest); margin:0 0 6px;
}
.app-redesign .ca-sub{ color:var(--text-2); font-size:13.5px; line-height:1.55; max-width:70ch; }
.app-redesign .ca-label{ font-size:12.5px; font-weight:600; color:var(--text-2); }
.app-redesign .ca-empty{
  margin-top:12px; padding:14px 16px; border-radius:var(--r-md);
  background:#fdf4e0; color:var(--warning); font-size:13.5px; line-height:1.5;
}
.app-redesign .ca-actions{ display:flex; }
.app-redesign .ca-actions .btn{ width:auto; }
@media(max-width:520px){ .app-redesign .ca-actions .btn{ width:100%; } }

/* What they already have. */
.app-redesign .campus-granted{ list-style:none; margin:12px 0 0; padding:0; display:grid; gap:10px; }
.app-redesign .campus-granted li{
  display:flex; align-items:center; gap:14px;
  padding:13px 15px; border:1px solid var(--border); border-radius:var(--r-md);
  background:var(--surface-alt);
}
.app-redesign .cg-badge{
  flex:none; width:38px; height:38px; border-radius:11px;
  background:var(--forest); color:var(--on-dark);
  display:flex; align-items:center; justify-content:center;
  font-size:12.5px; font-weight:600; letter-spacing:.02em;
}
.app-redesign .cg-body{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:1px; }
/* "Home campus" is two words in a chip; without this it breaks across them
   on a phone and the chip becomes a small square. */
.app-redesign .campus-granted .badge{ flex:none; white-space:nowrap; }
.app-redesign .cg-name{ font-size:14.5px; font-weight:500; color:var(--text); }
.app-redesign .cg-host{ font-size:12px; color:var(--text-3); }

/* The chooser. Each campus is a tile the width of the column it sits in, so
   the name wraps without the shape changing. */
.app-redesign .campus-choices{
  display:grid; gap:10px;
  grid-template-columns:repeat(auto-fill, minmax(250px, 1fr));
}
.app-redesign .campus-choice{
  position:relative; display:flex; align-items:center; gap:12px;
  padding:13px 14px; cursor:pointer;
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-md);
  transition:background .15s ease, border-color .15s ease, color .15s ease;
}
.app-redesign .campus-choice:hover{ border-color:var(--border-2); }
/* The real input stays in the DOM and stays focusable; the tile is the
   control you see. Keyboard focus is drawn on the tile instead. */
.app-redesign .campus-choice input[type=checkbox]{
  position:absolute; width:1px; height:1px; opacity:0; margin:0; pointer-events:none;
}
.app-redesign .campus-choice:has(input:focus-visible){ outline:2px solid var(--lime); outline-offset:2px; }
.app-redesign .cc-badge{
  flex:none; width:38px; height:38px; border-radius:11px;
  background:var(--surface-alt); color:var(--forest);
  display:flex; align-items:center; justify-content:center;
  font-size:12.5px; font-weight:600; letter-spacing:.02em;
  transition:background .15s ease, color .15s ease;
}
.app-redesign .cc-name{ flex:1 1 auto; min-width:0; font-size:14px; font-weight:500; line-height:1.35; }
.app-redesign .cc-tick{
  flex:none; width:22px; height:22px; border-radius:999px;
  border:1.5px solid var(--border-2);
  display:flex; align-items:center; justify-content:center;
  transition:background .15s ease, border-color .15s ease;
}
.app-redesign .cc-tick .ic{ width:13px; height:13px; opacity:0; transition:opacity .15s ease; }
.app-redesign .campus-choice:has(input:checked){
  background:var(--forest); border-color:var(--forest); color:var(--on-dark);
}
.app-redesign .campus-choice:has(input:checked) .cc-badge{ background:var(--on-dark); color:var(--forest); }
.app-redesign .campus-choice:has(input:checked) .cc-tick{ background:var(--lime); border-color:var(--lime); }
.app-redesign .campus-choice:has(input:checked) .cc-tick .ic{ opacity:1; fill:var(--on-lime); }

/* Past requests. */
.app-redesign .ca-requests{ list-style:none; margin:12px 0 0; padding:0; display:grid; gap:0; }
.app-redesign .ca-requests li{ padding:13px 0; border-top:1px solid var(--border); }
.app-redesign .ca-requests li:first-child{ border-top:0; padding-top:4px; }
.app-redesign .car-top{ display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.app-redesign .car-what{ font-size:14px; font-weight:500; }
.app-redesign .car-note{ margin:6px 0 0; font-size:13px; color:var(--text-2); }
.app-redesign .car-when{ font-size:12px; color:var(--text-3); }

/* LISTINGS HEADER — count + sort */
.app-redesign .listings-header{
  display:flex; justify-content:space-between; align-items:center;
  margin-bottom:24px; padding-bottom:16px; border-bottom:1px solid var(--border);
}
.app-redesign .listings-count{ font-size:15px; color:var(--text-2); }
.app-redesign .sort-select{
  padding:10px 14px; background:var(--white); border:1px solid var(--border);
  border-radius:var(--r-md); color:var(--text); font-size:14px; font-family:'Inter', sans-serif;
}

/* GRID */
.app-redesign .listings-grid{
  display:grid; grid-template-columns:1fr; gap:26px; margin-bottom:50px;
}
@media(min-width:640px){ .app-redesign .listings-grid{ grid-template-columns:repeat(2, 1fr); } }
@media(min-width:1080px){ .app-redesign .listings-grid{ grid-template-columns:repeat(3, 1fr); } }
@media(min-width:1400px){ .app-redesign .listings-grid{ grid-template-columns:repeat(4, 1fr); } }

/* PROPERTY CARD */
.app-redesign .property-card{
  position:relative; background:var(--white); border:1px solid var(--border);
  border-radius:var(--r-lg); overflow:hidden; box-shadow:var(--sh-sm);
  display:flex; flex-direction:column; height:100%;
  transition:transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.app-redesign .property-card:hover{
  transform:translateY(-6px); box-shadow:var(--sh); border-color:var(--border-2);
}
.app-redesign .property-image{
  width:100%; height:200px; object-fit:cover; border-bottom:1px solid var(--border); display:block;
}
/* The photograph and everything pinned to it. This is the positioning context
   for the badges and the menu, so they follow the image when its height
   changes instead of being measured against the card. */
.app-redesign .property-media{ position:relative; }
.app-redesign .property-badge{
  position:absolute; top:14px; left:14px; z-index:2; display:inline-flex; align-items:center; gap:5px;
  background:var(--green); color:#fff; padding:5px 12px; border-radius:var(--pill);
  font-size:11.5px; font-weight:600; font-family:'Inter', sans-serif;
}
.app-redesign .property-badge .ic{ width:13px; height:13px; }
.app-redesign .property-content{ padding:20px; flex-grow:1; display:flex; flex-direction:column; }
.app-redesign .property-header{ margin-bottom:12px; }
.app-redesign .property-title{
  font-family:'Cormorant Garamond', serif; font-size:20px; font-weight:600; line-height:1.3;
  margin-bottom:4px; color:var(--forest);
}
.app-redesign .property-location{
  color:var(--text-2); font-size:13px; display:flex; align-items:center; gap:5px;
}
.app-redesign .property-location .ic{ color:var(--green); width:14px; height:14px; flex:none; }
.app-redesign .property-description{
  color:var(--text-2); font-size:13.5px; line-height:1.5; margin-bottom:16px; flex-grow:1;
}
.app-redesign .property-features{ display:flex; gap:14px; margin-bottom:18px; flex-wrap:wrap; }
.app-redesign .feature{ display:flex; align-items:center; gap:5px; color:var(--text-2); font-size:12.5px; }
.app-redesign .feature .ic{ color:var(--green); width:14px; height:14px; }
.app-redesign .property-footer{
  display:flex; justify-content:space-between; align-items:center; margin-top:auto; gap:10px;
}
.app-redesign .property-price{
  font-family:'Cormorant Garamond', serif; font-size:19px; font-weight:600; color:var(--forest);
}
.app-redesign .property-price span{
  font-size:12px; color:var(--text-2); font-weight:400; font-family:'Inter', sans-serif;
  /* The number and its unit are two words in one sentence, and inline spans
     get no gap between them: every card on the site read "₦550,000to move
     in". Not a phone bug — it was the same at every width, and only visible
     because the phone layout puts the price on its own line. */
  margin-left:5px;
}
.app-redesign .view-details{
  padding:9px 18px; background:var(--surface-alt); border:1px solid var(--border);
  border-radius:var(--pill); color:var(--text); font-weight:600; font-size:12.5px;
  font-family:'Inter', sans-serif; cursor:pointer; transition:background .2s ease, color .2s ease;
}
.app-redesign .view-details:hover{ background:var(--forest); color:var(--on-dark); }

/* THREE-DOT MENU */
.app-redesign .property-more-options{ position:absolute; top:14px; right:14px; z-index:10; }
.app-redesign .more-options-btn{
  width:30px; height:30px; border:none; border-radius:var(--pill); background:rgba(23,21,18,.55);
  color:#fff; cursor:pointer; display:flex; align-items:center; justify-content:center;
  transition:background .2s ease, transform .2s ease; backdrop-filter:blur(4px);
}
.app-redesign .more-options-btn:hover{ background:rgba(23,21,18,.8); transform:scale(1.08); }
.app-redesign .more-options-btn .ic{ width:16px; height:16px; transform:rotate(90deg); }
.app-redesign .options-dropdown{
  position:absolute; top:38px; right:0; background:var(--white); border:1px solid var(--border);
  border-radius:var(--r-md); padding:6px; min-width:170px; opacity:0; visibility:hidden;
  transform:translateY(-8px); transition:all .2s ease; box-shadow:var(--sh);
}
.app-redesign .property-more-options.active .options-dropdown{
  opacity:1; visibility:visible; transform:translateY(0);
}
.app-redesign .options-dropdown .save-property-btn,
.app-redesign .options-dropdown .share-property-btn{
  width:100%; display:flex; align-items:center; gap:9px; padding:9px 12px; background:none;
  border:none; border-radius:var(--r-sm); color:var(--text); font-size:13.5px;
  font-family:'Inter', sans-serif; cursor:pointer; transition:background .15s ease;
  text-align:left;
}
.app-redesign .options-dropdown .save-property-btn:hover,
.app-redesign .options-dropdown .share-property-btn:hover{ background:var(--mint); }
.app-redesign .options-dropdown .save-property-btn .ic,
.app-redesign .options-dropdown .share-property-btn .ic{ width:15px; height:15px; color:var(--green); flex:none; }
.app-redesign .options-dropdown .save-property-btn.saved{ color:var(--green); font-weight:600; }
.app-redesign .options-dropdown .save-property-btn.saved .sh-solid .ic{ fill:var(--green); }

/* ---------- Save: the heart fills ----------
   Both hearts are in the markup (see partials/save_heart.html) and this swaps
   them off the button's own .saved class. Two shapes rather than one recoloured
   path, because every icon in this set is an outline traced as a filled path —
   setting fill on the outline heart changes nothing you can see.

   A transition, not a swap: the outline shrinks away as the solid one settles
   in, so the change is legible while it happens rather than only afterwards. */
.app-redesign .save-heart{
  position:relative; display:inline-flex; flex:none;
  width:18px; height:18px;
}
/* Sized by the context the button is in, and the two shapes fill it exactly —
   they are stacked on top of each other, so anything but an exact match puts
   the solid heart a pixel off the outline it replaces. */
.app-redesign .options-dropdown .save-heart{ width:15px; height:15px; }
.app-redesign .pd-save-btn .save-heart{ width:19px; height:19px; }
.app-redesign .save-heart .sh-outline,
.app-redesign .save-heart .sh-solid{
  position:absolute; inset:0; display:inline-flex;
  align-items:center; justify-content:center;
  transition:opacity .22s ease, transform .3s cubic-bezier(.32,1.35,.5,1);
}
.app-redesign .save-heart .sh-outline .ic,
.app-redesign .save-heart .sh-solid .ic{ width:100%; height:100%; }
.app-redesign .save-heart .sh-solid{ opacity:0; transform:scale(.45); }

.app-redesign .saved .save-heart .sh-outline{ opacity:0; transform:scale(.55); }
.app-redesign .saved .save-heart .sh-solid{ opacity:1; transform:scale(1); }

/* One beat, on the tap that saved it. Added by the script and taken off again
   when it ends, so a page of already-saved rooms does not animate itself on
   load and the next save can run it again. */
@keyframes save-beat{
  0%{ transform:scale(1) }
  28%{ transform:scale(1.5) }
  52%{ transform:scale(.88) }
  74%{ transform:scale(1.12) }
  100%{ transform:scale(1) }
}
.app-redesign .is-beating .save-heart{ animation:save-beat .52s cubic-bezier(.32,1.4,.5,1); }
/* The fill carries the state; the movement is decoration. */
@media(prefers-reduced-motion:reduce){
  .app-redesign .is-beating .save-heart{ animation:none; }
  .app-redesign .save-heart .sh-outline,
  .app-redesign .save-heart .sh-solid{ transition:opacity .01s linear; }
}
/* Neither menu row wraps. "Save Property" and "Share listing" are one line
   each at every width a card gets; a wrapped one is what let a stray second
   text run sit between the halves of it and look like a rendering fault. */
.app-redesign .options-dropdown .save-label,
.app-redesign .options-dropdown .share-label{ white-space:nowrap; }

/* ============================================================
   CARD DENSITY — how many rooms fit across on a phone.

   One per row is the honest default on a narrow screen; two is what a
   student scanning a campus actually wants, because it doubles what they
   can see without scrolling. It is their call, so it is a control.

   The state lives as a class on <html>, set by a small inline script in the
   page head before the first paint. Anything applied after paint shows the
   cards rearranging themselves, which looks like a bug even when it is the
   remembered preference.

   The button is hidden from 640px up: the grid already lays out two or more
   there, so there would be nothing left for it to choose.
   ============================================================ */
.app-redesign .listings-tools{ display:flex; align-items:center; gap:10px; }
/* A <select> is as wide as its longest option, and the campus one carries
   "Lagos State University of Science and Technology". Left alone it pushes
   the page 168px wide on a phone, so the selects are allowed to shrink and
   truncate instead of the layout being dragged along behind them. */
.app-redesign .listings-tools .sort-select{ min-width:0; flex:1 1 auto; }
@media(max-width:639px){
  .app-redesign .listings-tools{ width:100%; }
  .app-redesign .listings-tools .sort-select{ flex:1 1 40%; }
}
.app-redesign .density-toggle{
  display:none; align-items:center; justify-content:center;
  width:44px; height:44px; flex:none; padding:0;
  background:var(--surface-alt); border:1px solid var(--border); border-radius:var(--r-md);
  color:var(--text); cursor:pointer;
  transition:background .2s ease, border-color .2s ease, color .2s ease;
}
.app-redesign .density-toggle:hover{ border-color:var(--border-2); }
.app-redesign .density-toggle .ic{ width:18px; height:18px; }
.app-redesign .density-toggle .dt-icon{ display:inline-flex; }
/* The icon shows the layout you are looking at, as the store does: a list when
   the cards are stacked, a grid when they sit two across. */
.app-redesign .density-toggle .dt-icon-grid{ display:none; }
html.listings-dense .app-redesign .density-toggle{
  background:var(--forest); border-color:var(--forest); color:var(--on-dark);
}
html.listings-dense .app-redesign .density-toggle .dt-icon-list{ display:none; }
html.listings-dense .app-redesign .density-toggle .dt-icon-grid{ display:inline-flex; }

@media(max-width:639px){
  .app-redesign .density-toggle{ display:inline-flex; }
  /* "Showing 6 properties" and the sort control no longer fit side by side
     once the button joins them on a 360px screen. */
  .app-redesign .listings-header{ flex-wrap:wrap; gap:12px; }
  .app-redesign .listings-tools{ margin-left:auto; }

  /* Two up. The card keeps the photograph and the rent — the two things a
     student scans for — and gives up the prose, which is what the detail page
     is for. */
  html.listings-dense .app-redesign .listings-grid{
    grid-template-columns:repeat(2, 1fr); gap:12px;
  }
  /* The menu inside a card is narrower than a card here, and a card can be
     136px, so the card has to stop clipping its own corners; the image is
     rounded instead. */
  html.listings-dense .app-redesign .property-card{
    overflow:visible; border-radius:var(--r-md);
    /* A grid item will not shrink below its content unless told to, and the
       address line below is nowrap — which set a 176px floor and pushed the
       page 105px wide on a 320px phone. Everything inside that can be too
       wide already truncates or wraps on its own. */
    min-width:0;
  }
  html.listings-dense .app-redesign .property-image{
    height:112px; border-radius:calc(var(--r-md) - 1px) calc(var(--r-md) - 1px) 0 0;
  }
  html.listings-dense .app-redesign .property-content{ padding:11px; }
  html.listings-dense .app-redesign .property-header{ margin-bottom:8px; }
  html.listings-dense .app-redesign .property-title{
    font-size:15.5px; line-height:1.25; margin-bottom:2px;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  }
  html.listings-dense .app-redesign .property-location{
    font-size:11px; gap:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; display:block;
  }
  html.listings-dense .app-redesign .property-location .ic{
    width:12px; height:12px; vertical-align:-2px; margin-right:3px;
  }
  html.listings-dense .app-redesign .property-description{ display:none; }
  /* "1 Bed · 1 Bath" is the shape of the place; the rest is detail-page work.
     The row is capped by hiding from the third item on, so a listing with no
     WiFi still shows its type. */
  html.listings-dense .app-redesign .property-features{ gap:8px; margin-bottom:10px; }
  html.listings-dense .app-redesign .property-features .feature:nth-child(n+3){ display:none; }
  html.listings-dense .app-redesign .feature{ font-size:11px; }
  html.listings-dense .app-redesign .feature .ic{ width:12px; height:12px; }
  html.listings-dense .app-redesign .property-footer{ flex-direction:column; align-items:stretch; gap:7px; }
  html.listings-dense .app-redesign .property-price{ font-size:16px; }
  html.listings-dense .app-redesign .property-price span{ display:block; font-size:10.5px; }
  html.listings-dense .app-redesign .view-details{ text-align:center; padding:8px 10px; font-size:11.5px; }
  html.listings-dense .app-redesign .property-badge{ top:8px; left:8px; padding:3px 8px; font-size:10px; }
  html.listings-dense .app-redesign .property-badge .ic{ width:11px; height:11px; }
  /* Anchored to the image, not to a number — this is the rule that used to be
     top:172px against a 112px photograph, which put "2 rooms left" on top of
     the location line. */
  html.listings-dense .app-redesign .property-units{ bottom:8px; left:8px; font-size:10px; padding:3px 7px; }
  html.listings-dense .app-redesign .property-more-options{ top:8px; right:8px; }
  html.listings-dense .app-redesign .more-options-btn{ width:26px; height:26px; }
  html.listings-dense .app-redesign .more-options-btn .ic{ width:13px; height:13px; }
  html.listings-dense .app-redesign .options-dropdown{ min-width:128px; padding:4px; }
  html.listings-dense .app-redesign .options-dropdown .save-property-btn,
  html.listings-dense .app-redesign .options-dropdown .share-property-btn{ padding:8px; font-size:12px; gap:6px; }
  /* The lift is a mouse affordance. In a tight grid under a thumb it reads as
     the card jumping about. */
  html.listings-dense .app-redesign .property-card:hover{ transform:none; box-shadow:var(--sh-sm); }
}

/* ============================================================
   Property detail page — structure ported from the reference
   design at drentals.ng/listings/1 (dark glass + emerald), colors
   remapped to the cream/ink/olive brand. Classes prefixed "pd-"
   since the reference reused names (.property-title etc.) that
   already belong to the listing-card CSS above.
   ============================================================ */

/* HEADER */
.app-redesign .pd-header{ margin:0 0 28px; }
.app-redesign .pd-breadcrumb{
  display:flex; align-items:center; gap:8px; color:var(--text-2); font-size:13px; margin-bottom:20px; flex-wrap:wrap;
}
.app-redesign .pd-breadcrumb a{ color:var(--text-2); transition:color .2s ease; }
.app-redesign .pd-breadcrumb a:hover{ color:var(--forest); }
.app-redesign .pd-breadcrumb strong{ color:var(--forest); font-weight:600; }
.app-redesign .pd-title-section{
  display:flex; justify-content:space-between; align-items:flex-start; gap:20px; flex-wrap:wrap;
}
.app-redesign .pd-title-wrapper{ flex:1; min-width:260px; }
.app-redesign .pd-title{
  font-family:'Cormorant Garamond', serif; font-size:clamp(28px, 4vw, 40px); font-weight:600;
  line-height:1.2; margin-bottom:10px; color:var(--forest);
}
.app-redesign .pd-location{ display:flex; align-items:center; gap:7px; color:var(--text-2); font-size:14px; }
.app-redesign .pd-location .ic{ color:var(--green); width:15px; height:15px; flex:none; }
.app-redesign .pd-status{
  display:inline-flex; align-items:center; gap:6px; background:var(--green); color:#fff;
  padding:6px 14px; border-radius:var(--pill); font-size:12.5px; font-weight:600; margin-top:12px;
}
.app-redesign .pd-price-section{ text-align:right; min-width:200px; }
.app-redesign .pd-price{ font-family:'Cormorant Garamond', serif; font-size:clamp(26px, 3.4vw, 36px); font-weight:600; color:var(--forest); }
.app-redesign .pd-price-period{ font-size:13.5px; color:var(--text-2); }

/* IMAGE CAROUSEL */
.app-redesign .pd-carousel{
  position:relative; width:100%; height:320px; border-radius:var(--r-lg); overflow:hidden;
  margin:26px 0 36px; background:var(--surface-alt); box-shadow:var(--sh-sm);
}
.app-redesign .pd-carousel-container{ width:100%; height:100%; position:relative; }
.app-redesign .pd-slide{
  width:100%; height:100%; position:absolute; top:0; left:0; opacity:0; transition:opacity .5s ease;
}
.app-redesign .pd-slide.active{ opacity:1; }
.app-redesign .pd-slide-image{ width:100%; height:100%; object-fit:cover; display:block; }
/* ---------- the filmstrip ---------------------------------------------
   A walkthrough is shot on a phone held upright, so its stills are 9:16 and
   the letterbox above keeps about a fifth of each one — the rest cropped away
   and the remainder magnified into a patch of wall. Showing one frame whole
   fixed the crop and left a narrow strip marooned in a wide page.

   So a gallery of upright frames is not a slideshow. It is a continuous band
   of frames running past both edges, the one nearest the middle standing a
   little taller, looping without a seam. The band is the width of the page,
   so the space either side of a single frame stops existing. */
.app-redesign .pd-carousel.pd-carousel--filmstrip{
  --film-h:clamp(240px, 34vh, 380px);
  height:auto; border-radius:0; background:none; overflow:hidden;
  cursor:grab; touch-action:pan-y;
}
.app-redesign .pd-carousel--filmstrip:active{ cursor:grabbing; }
/* Not text, and not an image the browser should try to drag instead. */
.app-redesign .pd-carousel--filmstrip .pd-slide-image{
  user-select:none; -webkit-user-drag:none;
}
.app-redesign .pd-carousel--filmstrip .pd-carousel-container{
  position:relative; height:var(--film-h);
  display:flex; align-items:center; width:max-content;
  will-change:transform;
}
/* The slides stop being stacked and faked into a fade, and become a row.

   Each frame takes the shape of the phone that shot it rather than the shape
   of its own file, so a frame that is not quite 9:16 loses a sliver to
   `cover` instead of refusing to lay out at all. Sizing the row from the
   image's intrinsic width looked obvious and gave 1462px frames. */
.app-redesign .pd-carousel--filmstrip .pd-slide{
  position:relative; inset:auto; opacity:1; flex:0 0 auto;
  /* The width is stated rather than derived. `aspect-ratio` with `height:100%`
     looked right and lost to the flex item's automatic minimum size, which is
     the image's own 1280px — every frame came out 1345px wide. */
  height:100%; width:calc(var(--film-h) * 0.5625); min-width:0; padding:0 1px;
  transition:transform .18s ease-out;
}
.app-redesign .pd-carousel--filmstrip .pd-slide-image{
  width:100%; height:100%; object-fit:cover; border-radius:10px;
}
/* Arrows and dots belong to a slideshow; a band that never ends has neither. */
.app-redesign .pd-carousel--filmstrip .pd-carousel-nav,
.app-redesign .pd-carousel--filmstrip .pd-carousel-dots{ display:none; }
.app-redesign .pd-video-overlay{
  position:absolute; inset:0; z-index:3; display:flex; align-items:center; justify-content:center;
  background:rgba(23,21,18,.25); cursor:pointer;
}
.app-redesign .pd-video-overlay .ic{ width:56px; height:56px; color:#fff; filter:drop-shadow(0 4px 10px rgba(0,0,0,.4)); }
.app-redesign .pd-carousel-nav{
  position:absolute; top:0; left:0; width:100%; height:100%; display:flex;
  justify-content:space-between; align-items:center; padding:0 16px; pointer-events:none;
}
.app-redesign .pd-carousel-btn{
  pointer-events:auto; background:rgba(23,21,18,.55); border:none; color:#fff; width:42px; height:42px;
  border-radius:var(--pill); display:flex; align-items:center; justify-content:center; cursor:pointer;
  transition:all .2s ease; z-index:10; backdrop-filter:blur(4px);
}
.app-redesign .pd-carousel-btn:hover{ background:rgba(23,21,18,.8); transform:scale(1.08); }
.app-redesign .pd-carousel-dots{
  position:absolute; bottom:16px; left:0; width:100%; display:flex; justify-content:center; gap:8px; z-index:10;
}
.app-redesign .pd-dot{
  width:9px; height:9px; background:rgba(255,255,255,.55); border-radius:50%; cursor:pointer; transition:all .2s ease;
}
.app-redesign .pd-dot.active{ background:#fff; transform:scale(1.25); }
@media(min-width:900px){ .app-redesign .pd-carousel{ height:460px; } }

/* VIDEO MODAL */
.app-redesign .pd-video-modal{
  display:none; position:fixed; inset:0; z-index:200; background:rgba(23,21,18,.85);
  align-items:center; justify-content:center; padding:20px;
}
.app-redesign .pd-video-modal.active{ display:flex; }
.app-redesign .pd-video-modal-content{ position:relative; width:100%; max-width:860px; }
.app-redesign .pd-video-modal-player{ width:100%; border-radius:var(--r-md); display:block; }
.app-redesign .pd-video-modal-close{
  position:absolute; top:-40px; right:0; background:none; border:none; color:#fff; font-size:30px;
  cursor:pointer; line-height:1;
}

/* CONTENT LAYOUT */
.app-redesign .pd-layout{ display:grid; grid-template-columns:1fr; gap:32px; margin-bottom:60px; }
@media(min-width:900px){ .app-redesign .pd-layout{ grid-template-columns:1fr 380px; } }

/* LEFT COLUMN */
.app-redesign .pd-main{
  background:var(--white); border-radius:var(--r-lg); padding:28px; border:1px solid var(--border); box-shadow:var(--sh-sm);
}
@media(min-width:900px){ .app-redesign .pd-main{ padding:38px; } }
.app-redesign .pd-section-title{
  font-family:'Cormorant Garamond', serif; font-size:22px; font-weight:600; margin-bottom:18px;
  display:flex; align-items:center; gap:10px; color:var(--forest);
}
.app-redesign .pd-section-title .ic{ color:var(--green); width:19px; height:19px; }
.app-redesign .pd-description{ color:var(--text-2); line-height:1.7; margin-bottom:36px; font-size:15px; }

.app-redesign .pd-features-grid{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(140px, 1fr)); gap:16px; margin-bottom:36px;
}
.app-redesign .pd-feature{
  background:var(--surface-alt); border-radius:var(--r-md); padding:18px; display:flex; flex-direction:column;
  align-items:center; text-align:center; transition:transform .2s ease, background .2s ease;
}
.app-redesign .pd-feature:hover{ background:var(--mint); transform:translateY(-3px); }
.app-redesign .pd-feature-icon{ color:var(--green); margin-bottom:12px; }
.app-redesign .pd-feature-icon .ic{ width:24px; height:24px; }
.app-redesign .pd-feature-name{ font-weight:600; font-size:13.5px; color:var(--forest); margin-bottom:4px; }
.app-redesign .pd-feature-value{ color:var(--text-2); font-size:12.5px; }

.app-redesign .pd-amenities{ margin-bottom:36px; }
.app-redesign .pd-amenities-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(180px, 1fr)); gap:12px; }
.app-redesign .pd-amenity{
  display:flex; align-items:center; gap:9px; padding:11px 14px; background:var(--surface-alt);
  border-radius:var(--r-sm); transition:background .2s ease; font-size:13.5px; color:var(--text);
}
.app-redesign .pd-amenity:hover{ background:var(--mint); }
.app-redesign .pd-amenity .ic{ color:var(--green); width:16px; height:16px; flex:none; }

.app-redesign .pd-rules{
  background:#eef1e8; border-left:4px solid var(--green); padding:20px 22px; border-radius:var(--r-md); margin-top:8px;
}
.app-redesign .pd-rules h3{ font-family:'Inter', sans-serif; font-size:14.5px; font-weight:700; color:var(--forest); display:flex; align-items:center; gap:8px; }
.app-redesign .pd-rules h3 .ic{ color:var(--green); width:16px; height:16px; }
.app-redesign .pd-rules-list{ list-style:none; margin-top:10px; }
.app-redesign .pd-rules-list li{ padding:6px 0; color:var(--text-2); display:flex; align-items:flex-start; gap:9px; font-size:13.5px; }
.app-redesign .pd-rules-list li .ic{ color:var(--green); width:15px; height:15px; margin-top:2px; flex:none; }

/* RIGHT COLUMN */
.app-redesign .pd-side{ display:flex; flex-direction:column; gap:18px; }
.app-redesign .pd-agent-card{
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg); padding:26px; box-shadow:var(--sh-sm);
}
.app-redesign .pd-agent-header{
  display:flex; align-items:center; gap:14px; margin-bottom:18px; padding-bottom:18px; border-bottom:1px solid var(--border);
}
.app-redesign .pd-agent-avatar{
  width:52px; height:52px; background:var(--forest); color:var(--on-dark); border-radius:50%;
  display:flex; align-items:center; justify-content:center; font-weight:600; font-size:19px; flex:none;
  font-family:'Cormorant Garamond', serif;
}
.app-redesign .pd-agent-name{ font-size:17px; font-weight:600; color:var(--forest); margin-bottom:3px; }
.app-redesign .pd-agent-role{ color:var(--green); font-size:12.5px; font-weight:600; }
.app-redesign .pd-agent-company{ color:var(--text-2); font-size:13px; display:flex; align-items:center; gap:7px; margin-bottom:14px; }
.app-redesign .pd-agent-company .ic{ color:var(--green); width:14px; height:14px; flex:none; }
.app-redesign .pd-agent-phone{
  margin-bottom:16px; padding:11px; background:#eef1e8; border-radius:var(--r-sm); text-align:center;
}
.app-redesign .pd-agent-phone a{ color:var(--forest); text-decoration:none; font-size:14.5px; font-weight:600; display:inline-flex; align-items:center; gap:7px; }
.app-redesign .pd-agent-phone .ic{ width:15px; height:15px; color:var(--green); }
.app-redesign .pd-contact-buttons{ display:flex; flex-direction:column; gap:12px; }
.app-redesign .pd-contact-btn{
  padding:14px; border-radius:var(--r-md); font-weight:600; font-size:14px; cursor:pointer;
  transition:all .2s ease; border:none; display:flex; align-items:center; justify-content:center; gap:9px; text-decoration:none;
}
.app-redesign .pd-message-btn{ background:var(--forest); color:var(--on-dark); }
.app-redesign .pd-message-btn:hover{ transform:translateY(-2px); box-shadow:var(--sh); }

.app-redesign .pd-actions{
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg); padding:26px; box-shadow:var(--sh-sm);
}
.app-redesign .pd-actions h3{ font-size:14.5px; font-weight:700; color:var(--forest); margin-bottom:16px; display:flex; align-items:center; gap:8px; font-family:'Inter', sans-serif; }
.app-redesign .pd-actions h3 .ic{ color:var(--green); width:16px; height:16px; }
.app-redesign .pd-action-buttons{ display:flex; flex-direction:column; gap:12px; }
/* Share, in the topbar. An icon button because the label is a screen reader's
   business here — the shape is the message, and the phone's own sheet does the
   naming once it opens. */
.app-redesign .topbar-share{
  width:40px; height:40px; flex:none; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  background:var(--white); border:1px solid var(--border);
  border-radius:var(--pill); color:var(--text); cursor:pointer;
  transition:background .18s ease, border-color .18s ease, transform .18s ease;
}
.app-redesign .topbar-share:hover{ background:var(--mint); border-color:var(--border-2); }
.app-redesign .topbar-share:active{ transform:scale(.92); }
.app-redesign .topbar-share .ic{ width:18px; height:18px; }
.app-redesign .topbar-share:focus-visible{ outline:2px solid var(--lime-dark); outline-offset:2px; }

/* ---------- the rent split, on the listing ----------
   A room that only works split two ways is the one fact a student needs before
   they fall for the photographs. Said once, above the fold of the sidebar, with
   the share already worked out. */
.app-redesign .pd-split{
  margin-top:16px; padding:16px 18px;
  background:var(--white); border:1px solid var(--border);
  border-left:3px solid var(--lime-dark); border-radius:var(--r-md);
}
.app-redesign .pd-split.is-quiet{ border-left-color:var(--border-2); background:transparent; }
.app-redesign .pd-split-head{ display:flex; align-items:flex-start; gap:11px; }
.app-redesign .pd-split-head .ic{ flex:none; width:18px; height:18px; color:var(--lime-dark); margin-top:2px; }
.app-redesign .pd-split-head strong{ font-size:14.5px; }
.app-redesign .pd-split-bar{
  height:6px; margin-top:12px; border-radius:999px; overflow:hidden;
  background:var(--surface-alt);
}
.app-redesign .pd-split-bar span{ display:block; height:100%; background:var(--lime-dark); }

.app-redesign .pd-save-btn{
  padding:14px; background:var(--surface-alt); border:1px solid var(--border); border-radius:var(--r-md);
  color:var(--text); font-weight:600; font-size:14px; cursor:pointer; transition:all .2s ease;
  display:flex; align-items:center; justify-content:center; gap:9px; text-decoration:none;
}
.app-redesign .pd-save-btn:hover{ background:var(--mint); transform:translateY(-2px); }
.app-redesign .pd-save-btn.saved{ background:var(--green); border-color:var(--green); color:#fff; }
.app-redesign .pd-save-btn.saved .ic{ fill:#fff; }
.app-redesign .pd-whatsapp-btn{ background:#25D366; border-color:#25D366; color:#fff; }
.app-redesign .pd-whatsapp-btn:hover{ background:#1fb856; transform:translateY(-2px); }

/* ============================================================
   AGENT / LANDLORD DASHBOARD
   The first screen a lister sees after signing in. Same cream
   surface + ink type as the rest of the shell; the only new
   shapes here are the stat row, the two-column split and the
   quick-action tiles.
   ============================================================ */

.app-redesign .dash-head{
  display:flex; justify-content:space-between; align-items:flex-start;
  flex-wrap:wrap; gap:16px; margin-bottom:26px;
}
.app-redesign .dash-eyebrow{
  font-size:11.5px; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:var(--green); margin:0 0 8px;
}
.app-redesign .dash-title{
  font-family:'Cormorant Garamond', serif; font-weight:500; letter-spacing:-.015em;
  font-size:32px; line-height:1.1; margin:0 0 8px;
}
@media(min-width:768px){ .app-redesign .dash-title{ font-size:38px; } }

.app-redesign .dash-alert{
  display:inline-flex; align-items:center; gap:9px; padding:11px 16px;
  border-radius:var(--pill); background:var(--forest); color:var(--on-dark);
  font-size:13.5px; white-space:nowrap;
  /* A pill is sized for a count. Never wider than the page it sits in, even
     if somebody puts a paragraph in one. */
  max-width:100%;
}
.app-redesign .dash-alert .ic{ width:17px; height:17px; color:var(--lime); }
.app-redesign .dash-alert > span{ min-width:0; overflow:hidden; text-overflow:ellipsis; }

/* The same control carrying a sentence instead of a count. nowrap is the
   whole point of the pill above and the whole problem with a sentence in it:
   "Verify your school email to message agents, save rooms and book a drone
   tour." is one line about 500px long, which on a 390px phone pushed the
   entire dashboard sideways. */
.app-redesign .dash-alert.is-block{
  display:flex; align-items:flex-start; white-space:normal;
  border-radius:var(--r-md); line-height:1.45; text-align:left;
}
.app-redesign .dash-alert.is-block .ic{ flex:none; margin-top:2px; }

/* ---------- dashboards: section headings ----------
   "Newest near …" sat flush against the top of the card grid — close enough
   that the card's border read as an underline. The heading needs its own air
   underneath; the sections already space themselves above. */
.app-redesign .dash-h2{ font-size:19px; margin:0 0 14px; }
   One row per tour, and every part of it allowed to shrink. These were drawn
   with .dash-alert, so a listing title became an unbreakable line wider than
   the screen and the row was sliced off at both ends. */
.app-redesign .dash-tours{
  display:flex; flex-direction:column; gap:10px; margin-top:14px;
}
.app-redesign .dash-tour{
  display:flex; align-items:center; gap:12px; padding:13px 16px; min-width:0;
  border:1px solid var(--border); background:var(--white);
  border-radius:var(--r-md); color:var(--text); text-decoration:none;
  transition:border-color .18s ease, box-shadow .18s ease;
}
.app-redesign .dash-tour:hover{ border-color:var(--border-2); box-shadow:var(--sh-sm); }
.app-redesign .dash-tour-ic{ flex:none; display:inline-flex; color:var(--lime-dark); }
.app-redesign .dash-tour-ic .ic{ width:17px; height:17px; }
.app-redesign .dash-tour-text{
  flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:2px;
}
.app-redesign .dash-tour-text strong{
  font-weight:600; font-size:14px; line-height:1.35;
  /* Long listing titles break rather than stretch the row: overflow-wrap
     anywhere, because a single unbroken word is the case that still overflows. */
  overflow-wrap:anywhere;
}
.app-redesign .dash-tour-text small{ font-size:12.5px; color:var(--text-2); }
.app-redesign .dash-tour-go{ flex:none; display:inline-flex; color:var(--text-3); }
.app-redesign .dash-tour-go .ic{ width:15px; height:15px; }

/* ---------- stat row ---------- */
.app-redesign .dash-stats{
  display:grid; grid-template-columns:repeat(2, 1fr); gap:14px; margin-bottom:18px;
}
@media(min-width:900px){ .app-redesign .dash-stats{ grid-template-columns:repeat(4, 1fr); } }
.app-redesign .dash-stats .stat{
  border:1px solid var(--border); background:var(--white); border-radius:var(--r-lg); padding:20px;
}
.app-redesign .dash-stats .stat.dark{
  background:linear-gradient(165deg, #202519 0%, #171a12 100%); border-color:transparent;
}
.app-redesign .dash-stats .stat .v{ font-size:30px; line-height:1; }
.app-redesign .dash-stats .stat .sic{ margin-bottom:4px; }

.app-redesign .dash-pills{ display:flex; flex-wrap:wrap; gap:10px; margin-bottom:24px; }

/* ---------- two-column split ---------- */
.app-redesign .dash-cols{ display:grid; grid-template-columns:1fr; gap:20px; margin-bottom:24px; }
@media(min-width:1024px){ .app-redesign .dash-cols{ grid-template-columns:1.35fr 1fr; } }

.app-redesign .dash-card-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding-bottom:14px; margin-bottom:6px; border-bottom:1px solid var(--border);
}
.app-redesign .dash-card-head h2{ font-size:22px; margin:0; }
.app-redesign .dash-more{
  display:inline-flex; align-items:center; gap:6px; font-size:13px; font-weight:500; color:var(--green);
}
.app-redesign .dash-more .ic{ width:14px; height:14px; }

/* ---------- rows ---------- */
.app-redesign .dash-row{
  display:flex; align-items:center; gap:13px; padding:14px 0;
  border-bottom:1px solid var(--border);
}
.app-redesign .dash-row:last-child{ border-bottom:0; }
.app-redesign .dash-thumb{
  width:52px; height:52px; flex:none; border-radius:var(--r-sm);
  background:var(--surface-alt) center/cover no-repeat;
}
.app-redesign .dash-avatar{
  width:40px; height:40px; flex:none; border-radius:var(--pill);
  background:var(--surface-alt); color:var(--text-2);
  display:flex; align-items:center; justify-content:center;
  font-weight:600; font-size:15px;
}
.app-redesign .dash-row-title{
  display:block; font-weight:500; font-size:14.5px; color:var(--forest); line-height:1.35;
}
.app-redesign a.dash-row:hover .dash-row-title,
.app-redesign .dash-row a.dash-row-title:hover{ color:var(--green); }
.app-redesign .dash-unread{
  flex:none; min-width:22px; height:22px; padding:0 7px; border-radius:var(--pill);
  background:var(--forest); color:var(--on-dark);
  display:flex; align-items:center; justify-content:center; font-size:11.5px; font-weight:600;
}
@media(max-width:520px){ .app-redesign .hide-tight{ display:none; } }

/* ---------- empty states ---------- */
.app-redesign .dash-empty{ text-align:center; padding:34px 12px 18px; }
.app-redesign .dash-empty-ic{
  width:48px; height:48px; border-radius:var(--pill); background:var(--surface-alt);
  display:inline-flex; align-items:center; justify-content:center; margin-bottom:12px;
}
.app-redesign .dash-empty-ic .ic{ width:22px; height:22px; color:var(--green); }
.app-redesign .dash-empty-title{
  font-family:'Cormorant Garamond', serif; font-size:21px; font-weight:500; margin:0 0 6px;
}
.app-redesign .dash-empty .btn{ margin-top:14px; }

/* ---------- quick actions ---------- */
.app-redesign .dash-actions{ display:grid; grid-template-columns:1fr; gap:14px; }
@media(min-width:768px){ .app-redesign .dash-actions{ grid-template-columns:repeat(3, 1fr); } }
.app-redesign .dash-action{
  display:flex; align-items:center; gap:14px; padding:18px;
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg);
  box-shadow:var(--sh-sm); transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.app-redesign .dash-action:hover{ transform:translateY(-3px); box-shadow:var(--sh); border-color:var(--border-2); }
.app-redesign .dash-action-ic{
  width:42px; height:42px; flex:none; border-radius:var(--r-sm); background:var(--surface-alt);
  display:flex; align-items:center; justify-content:center;
}
.app-redesign .dash-action-ic .ic{ width:19px; height:19px; color:var(--green); }
.app-redesign .dash-action strong{ display:block; font-size:14.5px; font-weight:600; color:var(--forest); }
.app-redesign .dash-action small{ display:block; font-size:12px; color:var(--text-2); margin-top:3px; }

/* ============================================================
   NEW / EDIT LISTING FORM
   Grouped into numbered sections so a long form reads as five
   short ones. Same cream card surface as the dashboard.
   ============================================================ */

.app-redesign .lf-wrap{ max-width:880px; }
.app-redesign .lf-head{ margin-bottom:26px; }

.app-redesign .lf-alert{
  display:flex; gap:10px; align-items:flex-start; padding:14px 16px; margin-bottom:20px;
  border-radius:var(--r-md); background:#f7e7e0; color:var(--danger); font-size:13.5px;
}
.app-redesign .lf-alert .ic{ width:18px; height:18px; flex:none; color:var(--danger); }
.app-redesign .lf-alert ul{ margin:0; padding:0; list-style:none; }

.app-redesign .lf-form{ gap:20px; }

.app-redesign .lf-section{
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:24px; box-shadow:var(--sh-sm);
}
.app-redesign .lf-section-head{
  display:flex; gap:14px; align-items:flex-start;
  padding-bottom:16px; margin-bottom:20px; border-bottom:1px solid var(--border);
}
.app-redesign .lf-section-head h2{ font-size:22px; margin:0 0 3px; }
.app-redesign .lf-step{
  width:32px; height:32px; flex:none; border-radius:var(--pill);
  background:var(--forest); color:var(--on-dark);
  display:flex; align-items:center; justify-content:center;
  font-size:13px; font-weight:600;
}

.app-redesign .lf-grid{ display:grid; grid-template-columns:1fr; gap:18px; }
@media(min-width:700px){
  .app-redesign .lf-grid{ grid-template-columns:1fr 1fr; }
  .app-redesign .lf-grid .span-2{ grid-column:1 / -1; }
}

.app-redesign .lf-form input[type=file]{
  width:100%; padding:13px 15px; background:var(--surface-alt);
  border:1px dashed var(--border-2); border-radius:var(--r-md);
  font-size:13.5px; color:var(--text-2); cursor:pointer;
}
.app-redesign .lf-form input[type=file]:hover{ border-color:var(--green); }

.app-redesign .lf-check{
  display:inline-flex!important; align-items:center; gap:9px; font-weight:500!important;
  color:var(--text)!important; cursor:pointer;
}
.app-redesign .lf-req{
  font-size:10.5px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
  color:var(--green); margin-left:4px;
}

.app-redesign .lf-previews{ display:flex; flex-wrap:wrap; gap:10px; }
.app-redesign .lf-preview{
  width:84px; height:84px; object-fit:cover; border-radius:var(--r-sm);
  border:1px solid var(--border);
}

.app-redesign .lf-current{
  display:flex; gap:14px; align-items:center; padding:14px; margin-bottom:20px;
  background:var(--surface-alt); border-radius:var(--r-md);
}
.app-redesign .lf-current img{ width:76px; height:76px; object-fit:cover; border-radius:var(--r-sm); flex:none; }

.app-redesign .lf-actions{
  display:flex; justify-content:flex-end; gap:12px; flex-wrap:wrap;
}
@media(max-width:520px){ .app-redesign .lf-actions .btn{ flex:1; } }

/* ============================================================
   MY LISTINGS — the agent's own portfolio grid. Same card shape
   as the student-facing property card, but the overlay badge
   reports review/availability state and the footer carries the
   two actions an agent reaches for: edit, and mark taken.
   ============================================================ */

.app-redesign .ml-grid{ display:grid; grid-template-columns:1fr; gap:20px; }
@media(min-width:700px){ .app-redesign .ml-grid{ grid-template-columns:repeat(2, 1fr); } }
@media(min-width:1200px){ .app-redesign .ml-grid{ grid-template-columns:repeat(3, 1fr); } }

.app-redesign .ml-card{
  display:flex; flex-direction:column; background:var(--white);
  border:1px solid var(--border); border-radius:var(--r-lg); overflow:hidden;
  box-shadow:var(--sh-sm); transition:transform .2s ease, box-shadow .2s ease;
}
.app-redesign .ml-card:hover{ transform:translateY(-4px); box-shadow:var(--sh); }
.app-redesign .ml-media{
  position:relative; display:block; height:170px;
  background:var(--surface-alt) center/cover no-repeat;
  border-bottom:1px solid var(--border);
}
.app-redesign .ml-media .badge{ position:absolute; top:12px; left:12px; }

.app-redesign .ml-body{ padding:18px; display:flex; flex-direction:column; gap:8px; flex:1; }
.app-redesign .ml-title{
  font-family:'Cormorant Garamond', serif; font-size:20px; font-weight:600;
  line-height:1.25; color:var(--forest);
}
.app-redesign .ml-title:hover{ color:var(--green); }
.app-redesign .ml-loc{ display:flex; align-items:center; gap:6px; font-size:13px; color:var(--text-2); }
.app-redesign .ml-loc .ic{ width:14px; height:14px; color:var(--green); }
.app-redesign .ml-price{
  font-family:'Cormorant Garamond', serif; font-size:22px; font-weight:600; color:var(--green);
}
.app-redesign .ml-price small{ font-family:'Inter', sans-serif; font-size:11.5px; color:var(--text-3); font-weight:400; }
.app-redesign .ml-reject{
  font-size:12.5px; color:var(--danger); background:#f7e7e0;
  padding:9px 11px; border-radius:var(--r-sm); margin:0;
}
.app-redesign .ml-metrics{
  display:flex; gap:16px; padding-top:10px; margin-top:auto;
  border-top:1px solid var(--border); font-size:12.5px; color:var(--text-2);
}
.app-redesign .ml-metrics span{ display:inline-flex; align-items:center; gap:6px; }
.app-redesign .ml-metrics .ic{ width:14px; height:14px; color:var(--green); }
.app-redesign .ml-actions{ display:flex; gap:10px; padding-top:4px; }
.app-redesign .ml-actions form{ margin:0; }

/* ============================================================
   FOCUS PAGES — verification, onboarding steps. One centred
   column, a slim brand bar, no sidebar. Same cream tokens.
   ============================================================ */

.app-redesign.focus-page{ background:var(--bg); min-height:100vh; }

.app-redesign .focus-bar{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:18px 20px; background:var(--white); border-bottom:1px solid var(--border);
}
@media(min-width:768px){ .app-redesign .focus-bar{ padding:20px 32px; } }
.app-redesign .focus-logo{
  font-family:'Cormorant Garamond', serif; font-size:22px; font-weight:500;
  letter-spacing:-.01em; color:var(--forest);
}
.app-redesign .focus-step{ font-size:12.5px; color:var(--text-2); }

.app-redesign .focus-main{ display:flex; justify-content:center; padding:36px 16px 60px; }
.app-redesign .focus-col{ width:100%; max-width:720px; }

.app-redesign .focus-progress{ display:flex; gap:8px; margin-bottom:22px; }
.app-redesign .focus-progress span{ flex:1; height:5px; border-radius:var(--pill); background:var(--border-2); }
.app-redesign .focus-progress span.on{ background:var(--green); }

.app-redesign .focus-title{
  font-family:'Cormorant Garamond', serif; font-weight:500; letter-spacing:-.015em;
  font-size:30px; line-height:1.15; margin:0 0 8px;
}
@media(min-width:768px){ .app-redesign .focus-title{ font-size:36px; } }

.app-redesign .focus-badge{
  width:56px; height:56px; border-radius:var(--pill); background:var(--surface-alt);
  display:flex; align-items:center; justify-content:center; margin:0 auto 18px;
}
.app-redesign .focus-badge .ic{ width:24px; height:24px; color:var(--green); }

.app-redesign .focus-mailbox{
  display:flex; align-items:center; justify-content:center; gap:10px;
  padding:14px 16px; margin:18px 0; border-radius:var(--r-md);
  background:var(--surface-alt); border:1px solid var(--border);
  font-size:14px; word-break:break-all;
}
.app-redesign .focus-mailbox .ic{ width:18px; height:18px; color:var(--green); flex:none; }

.app-redesign .focus-actions{ display:flex; flex-wrap:wrap; gap:12px; justify-content:flex-end; margin-top:8px; }
@media(max-width:520px){ .app-redesign .focus-actions .btn{ flex:1; } }

/* ============================================================
   LISTING FORM — the WhatsApp-paste shortcut and the grouped
   amenity checklist. Same cream card surface as everything else.
   ============================================================ */

.app-redesign .lf-paste{
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:20px; margin-bottom:20px; box-shadow:var(--sh-sm);
}
.app-redesign .lf-paste-head{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
.app-redesign .lf-paste-head h2{ font-size:19px; margin:0 0 2px; }
.app-redesign .lf-paste-head > div{ flex:1; min-width:200px; }
.app-redesign .lf-paste-ic{
  width:42px; height:42px; flex:none; border-radius:var(--r-sm); background:var(--surface-alt);
  display:flex; align-items:center; justify-content:center;
}
.app-redesign .lf-paste-ic .ic{ width:19px; height:19px; color:var(--green); }
.app-redesign .lf-paste-body{ margin-top:16px; }
.app-redesign .lf-paste-body textarea{
  width:100%; padding:14px 15px; border-radius:var(--r-md);
  background:var(--surface-alt); border:1px solid var(--border);
  font:inherit; font-size:14px; color:var(--text); line-height:1.6; resize:vertical;
}
.app-redesign .lf-paste-body textarea:focus{
  outline:none; border-color:var(--green); box-shadow:0 0 0 3px rgba(142,156,117,.2);
}

/* ---------- grouped amenity checklist ---------- */
.app-redesign .lf-amgroup{ margin-bottom:20px; }
.app-redesign .lf-amgroup:last-of-type{ margin-bottom:0; }
.app-redesign .lf-amtitle{
  font-size:11.5px; font-weight:600; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text-2); margin:0 0 10px;
}
.app-redesign .lf-amgrid{ display:flex; flex-wrap:wrap; gap:9px; }
.app-redesign label.lf-am{
  display:inline-flex; align-items:center; gap:8px; cursor:pointer;
  padding:9px 14px; border-radius:var(--pill);
  background:var(--surface-alt); border:1px solid var(--border);
  font-family:var(--fb); font-size:13.5px; font-weight:400; color:var(--text);
  transition:background .15s ease, border-color .15s ease, color .15s ease;
}
.app-redesign label.lf-am:hover{ border-color:var(--border-2); }
.app-redesign label.lf-am input{ width:auto; margin:0; accent-color:var(--green); }
.app-redesign label.lf-am:has(input:checked){
  background:var(--forest); border-color:var(--forest); color:var(--on-dark);
}

/* ---------- Listing detail: landmark, flags and the cost breakdown ---------- */
.app-redesign .pd-landmark{
  display:flex; align-items:center; gap:6px; margin-top:6px;
  font-size:13px; color:var(--text-2);
}
.app-redesign .pd-landmark .ic{ width:14px; height:14px; color:var(--green); flex:none; }
.app-redesign .pd-flags{ display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
.app-redesign .pd-flag{
  display:inline-flex; align-items:center; gap:5px; padding:5px 11px;
  border-radius:var(--pill); background:var(--surface-alt); border:1px solid var(--border);
  font-size:12px; color:var(--text-2);
}
.app-redesign .pd-flag .ic{ width:13px; height:13px; color:var(--green); }
.app-redesign .pd-price-sub{ font-size:12.5px; color:var(--text-2); margin-top:4px; }

.app-redesign .pd-cost-table{
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg);
  overflow:hidden;
}
.app-redesign .pd-cost-row{
  display:flex; justify-content:space-between; align-items:baseline; gap:16px;
  padding:13px 18px; border-bottom:1px solid var(--border); font-size:14px;
}
.app-redesign .pd-cost-row:last-child{ border-bottom:0; }
.app-redesign .pd-cost-row span{ color:var(--text-2); }
.app-redesign .pd-cost-row strong{ font-weight:600; color:var(--forest); text-align:right; }
.app-redesign .pd-cost-total{ background:var(--surface-alt); }
.app-redesign .pd-cost-total strong{
  font-family:'Cormorant Garamond', serif; font-size:22px; font-weight:600; color:var(--green);
}
/* The recurring figure after a one-off move-in total. Set apart by a quiet
   rule and a lighter weight so it reads as "and then", not as a second price
   competing with the first — two prices that look like rivals was the whole
   failure of the old table. */
.app-redesign .pd-cost-sub{ background:var(--surface-alt); }
.app-redesign .pd-cost-sub span{ font-style:italic; }
.app-redesign .pd-cost-sub strong{ font-weight:500; color:var(--text-2); }
/* Inspection and utilities: facts about the viewing and the running cost, not
   line items in the bill. Their own row, their own icon, no amount column —
   "Inspection — Free" inside the money table made the one genuinely free
   thing on the page read like another charge. */
.app-redesign .pd-inspection{
  display:flex; gap:10px; align-items:flex-start; margin-top:10px;
  padding:12px 16px; border:1px solid var(--border); border-radius:var(--r-lg);
  background:var(--white); font-size:13.5px; color:var(--text-2); line-height:1.5;
}
.app-redesign .pd-inspection .ic{ width:16px; height:16px; color:var(--green); flex:none; margin-top:1px; }
.app-redesign .pd-inspection-text strong{ color:var(--forest); font-weight:600; }
.app-redesign .pd-cost-note{
  display:flex; gap:8px; align-items:flex-start; margin:12px 0 0;
  font-size:12.5px; color:var(--text-2); line-height:1.5;
}
.app-redesign .pd-cost-note .ic{ width:15px; height:15px; color:var(--green); flex:none; margin-top:1px; }

/* "3 rooms left" — the line that makes a student act on a card. Pinned to the
   foot of the photograph, so it stays on the photograph: the top-right corner
   belongs to the three-dot menu and the top-left to the Verified badge. */
.app-redesign .property-units{
  position:absolute; bottom:14px; left:14px; z-index:2;
  padding:5px 11px; border-radius:var(--pill);
  background:var(--forest); color:var(--on-dark);
  font-size:11.5px; font-weight:600; white-space:nowrap;
}

/* ── Listing visibility ──────────────────────────────────────────────
   The radio group on the upload form, and the per-row controls in the
   listings table. Mobile-first like the rest of this file: the actions
   row wraps rather than scrolling sideways on a phone. */
.lf-vis-group{display:grid;gap:10px}
.lf-vis-group label{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;
  border:1px solid var(--line);border-radius:var(--r-md);cursor:pointer;line-height:1.35}
.lf-vis-group label:hover{border-color:var(--forest)}
.lf-vis-group input[type=radio]{margin-top:3px;flex:none}

.ml-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.ml-avail{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.ml-alsolabel{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--ink-soft)}
.ml-visselect{padding:6px 10px;border:1px solid var(--line);border-radius:var(--pill);
  background:var(--surface);font:inherit;font-size:13px;max-width:100%}
.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}

/* The share-state banner on a listing the owner is previewing. */
.pd-visbanner{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:16px;
  padding:12px 14px;border-radius:var(--r-md);background:#e3e9f3;color:var(--forest);font-size:14px}
.pd-visbanner.is-draft{background:#e8e4db;color:var(--ink-soft)}

/* ---------- Notifications ------------------------------------------------
   The bell sits in the topbar on every app page. Until now the only signal
   the app gave was an unread badge on Messages, so a new room on your campus
   or a delivered drone tour reached nobody.                               */
.app-redesign .notif-bell{ position:relative; }
.app-redesign .notif-btn{
  position:relative; display:flex; align-items:center; justify-content:center;
  width:40px; height:40px; border-radius:999px; border:1px solid var(--border);
  background:var(--white); color:var(--text-1); cursor:pointer;
}
.app-redesign .notif-btn:hover{ background:var(--surface-2, rgba(0,0,0,.04)); }
.app-redesign .notif-badge{
  position:absolute; top:-4px; right:-4px; min-width:18px; height:18px; padding:0 5px;
  border-radius:999px; background:#c0392b; color:#fff; font-size:11px; font-weight:600;
  line-height:18px; text-align:center; border:2px solid var(--white);
}
.app-redesign .notif-badge.is-empty{ display:none; }

.app-redesign .notif-panel{
  position:absolute; top:calc(100% + 10px); right:0; z-index:70; width:360px;
  max-width:calc(100vw - 32px); background:var(--white); border:1px solid var(--border);
  border-radius:14px; box-shadow:0 18px 46px rgba(0,0,0,.18); overflow:hidden;
}
.app-redesign .notif-panel[hidden]{ display:none; }
.app-redesign .notif-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:12px 14px; border-bottom:1px solid var(--border);
}
.app-redesign .notif-readall{
  background:none; border:0; cursor:pointer; font-size:12.5px; color:var(--text-3);
}
.app-redesign .notif-readall:hover{ color:var(--text-1); text-decoration:underline; }
.app-redesign .notif-body{ max-height:min(60vh, 420px); overflow:auto; }
.app-redesign .notif-foot{
  display:block; padding:11px; text-align:center; font-size:13px;
  border-top:1px solid var(--border); color:var(--text-1);
}
.app-redesign .notif-foot:hover{ background:var(--surface-2, rgba(0,0,0,.04)); }

/* One row, shared by the dropdown and the full page. Each is a form, because
   marking read is a side effect and must not ride on a GET. */
.app-redesign .notif-item,
.app-redesign .notif-row{ border-bottom:1px solid var(--border); }
.app-redesign .notif-row:last-child,
.app-redesign .notif-item:last-child{ border-bottom:0; }
.app-redesign .notif-item button,
.app-redesign .notif-row button{
  display:flex; align-items:flex-start; gap:11px; width:100%; padding:12px 14px;
  background:none; border:0; cursor:pointer; text-align:left; color:var(--text-1);
}
.app-redesign .notif-item button:hover,
.app-redesign .notif-row button:hover{ background:var(--surface-2, rgba(0,0,0,.04)); }
.app-redesign .notif-item.is-unread,
.app-redesign .notif-row.is-unread{ background:rgba(46,125,50,.05); }
.app-redesign .notif-ic{
  flex:none; display:flex; align-items:center; justify-content:center;
  width:34px; height:34px; border-radius:10px; background:var(--surface-2, rgba(0,0,0,.05));
  color:var(--text-2);
}
.app-redesign .notif-ic-new_listing,
.app-redesign .notif-ic-listing_approved{ background:rgba(46,125,50,.12); color:#2e7d32; }
.app-redesign .notif-ic-listing_rejected{ background:rgba(192,57,43,.12); color:#c0392b; }
.app-redesign .notif-ic-message{ background:rgba(42,93,143,.12); color:#2a5d8f; }
.app-redesign .notif-ic-tour{ background:rgba(184,134,11,.14); color:#b8860b; }
.app-redesign .notif-text{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.app-redesign .notif-text strong{ font-size:13.5px; font-weight:600; }
.app-redesign .notif-body-text{
  font-size:12.5px; color:var(--text-2); overflow:hidden;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
}
.app-redesign .notif-when{ font-size:11.5px; color:var(--text-3); }
.app-redesign .notif-dot{
  flex:none; width:8px; height:8px; border-radius:999px; background:#2e7d32; margin-top:6px;
}
.app-redesign .notif-empty{ padding:26px 16px; text-align:center; }

/* A 360px panel would hang off the side of a phone. */
@media(max-width:520px){
  .app-redesign .notif-panel{ position:fixed; top:64px; left:16px; right:16px; width:auto; }
}

/* Unread count beside the sidebar's Notifications link. */
.app-redesign .snav-count{
  margin-left:auto; min-width:20px; padding:1px 6px; border-radius:999px;
  background:#c0392b; color:#fff; font-size:11px; font-weight:600; text-align:center;
}

/* ---------- Drone tour stream -------------------------------------------
   A 16:9 frame that holds its shape before the iframe loads, so the page
   does not jump when the player arrives.                                 */
.app-redesign .tr-stream{ margin-top:16px; }
.app-redesign .tr-frame{
  position:relative; width:100%; aspect-ratio:16/9; border-radius:var(--r-md);
  overflow:hidden; background:#000;
}
.app-redesign .tr-frame iframe{
  position:absolute; inset:0; width:100%; height:100%; border:0;
}
.app-redesign .tr-live{
  display:inline-flex; align-items:center; gap:6px; margin-bottom:8px;
  padding:3px 9px; border-radius:999px; background:#c0392b; color:#fff;
  font-size:11.5px; font-weight:700; letter-spacing:.04em;
  animation:tr-pulse 1.6s ease-in-out infinite;
}
@keyframes tr-pulse{ 0%,100%{opacity:1} 50%{opacity:.55} }
@media(prefers-reduced-motion:reduce){ .app-redesign .tr-live{ animation:none } }

/* ---------- Calendar picker ---------------------------------------------
   Used to pick a flight slot inside the window a student gave.            */
.app-redesign .cal{ border:1px solid var(--border); border-radius:var(--r-md);
  padding:12px; background:var(--white); max-width:330px; }
.app-redesign .cal-head{ display:flex; align-items:center; justify-content:space-between;
  gap:8px; margin-bottom:10px; }
.app-redesign .cal-month{ font-size:14px; }
.app-redesign .cal-nav{ background:none; border:1px solid var(--border); border-radius:8px;
  width:30px; height:30px; display:flex; align-items:center; justify-content:center;
  cursor:pointer; color:var(--text-1); }
.app-redesign .cal-nav:disabled{ opacity:.35; cursor:default; }
.app-redesign .cal-dow,
.app-redesign .cal-grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:3px; }
.app-redesign .cal-dow span{ text-align:center; font-size:11px; color:var(--text-3);
  padding-bottom:4px; }
.app-redesign .cal-day{ aspect-ratio:1; border:0; background:none; border-radius:8px;
  font-size:13px; cursor:pointer; color:var(--text-1); }
.app-redesign .cal-day:hover:not(:disabled){ background:var(--surface-2,rgba(0,0,0,.05)); }
.app-redesign .cal-day:disabled{ color:var(--text-3); opacity:.35; cursor:default; }
.app-redesign .cal-day.is-open{ box-shadow:inset 0 0 0 1px var(--green,#2e7d32); }
.app-redesign .cal-day.is-chosen{ background:var(--forest); color:var(--on-dark); }
.app-redesign .cal-times{ margin-top:12px; border-top:1px solid var(--border); padding-top:10px; }
.app-redesign .cal-times[hidden]{ display:none; }
.app-redesign .cal-slots{ display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.app-redesign .cal-slot{ border:1px solid var(--border); background:var(--white);
  border-radius:999px; padding:5px 11px; font-size:12.5px; cursor:pointer; color:var(--text-1); }
.app-redesign .cal-slot:disabled{ opacity:.35; cursor:default; }
.app-redesign .cal-slot.is-chosen{ background:var(--forest); color:var(--on-dark);
  border-color:var(--forest); }
.app-redesign .cal-chosen{ margin:10px 0 0; min-height:18px; color:var(--green,#2e7d32); }

/* ---------- Agent's drone queue -----------------------------------------
   A decision surface, not a list: the agent is being asked to allow a drone
   over a real compound, so the room, the money and the window a student gave
   all have to be visible without opening anything.                        */
.app-redesign .tq-heading{ font-size:19px; margin:26px 0 12px; display:flex;
  align-items:center; gap:9px; }
.app-redesign .tq-count{ font-family:var(--fd); font-size:12px; font-weight:700;
  background:var(--forest); color:var(--on-dark); border-radius:999px;
  min-width:22px; height:22px; display:inline-flex; align-items:center;
  justify-content:center; padding:0 7px; }

.app-redesign .tq-card{ display:flex; gap:0; background:var(--white);
  border:1px solid var(--border); border-radius:var(--r-md); overflow:hidden;
  margin-bottom:14px; }
.app-redesign .tq-card.is-pending{ border-left:3px solid var(--forest); }
.app-redesign .tq-card.is-quiet{ opacity:.9; }

.app-redesign .tq-media{ position:relative; flex:0 0 168px; min-height:150px; }
.app-redesign .tq-media img{ width:100%; height:100%; object-fit:cover; display:block; }
.app-redesign .tq-media-sm{ flex-basis:96px; min-height:74px; }
.app-redesign .tq-price{ position:absolute; left:10px; bottom:10px;
  background:rgba(0,0,0,.72); color:#fff; font-size:12.5px; font-weight:600;
  padding:3px 9px; border-radius:999px; }

.app-redesign .tq-body{ flex:1 1 auto; min-width:0; padding:14px 16px; }
.app-redesign .tq-top{ display:flex; align-items:flex-start; gap:10px;
  justify-content:space-between; }
.app-redesign .tq-title{ font-family:var(--fd); font-weight:700; font-size:15px;
  color:var(--text-1); text-decoration:none; line-height:1.3; }
.app-redesign a.tq-title:hover{ text-decoration:underline; }
.app-redesign .tq-mode{ flex:none; display:inline-flex; align-items:center; gap:5px;
  font-size:11.5px; padding:3px 9px; border-radius:999px;
  background:var(--surface-2,rgba(0,0,0,.05)); color:var(--text-2); }
.app-redesign .tq-mode.is-live{ background:rgba(192,57,43,.1); color:#c0392b; }
.app-redesign .tq-live{ flex:none; font-size:11px; font-weight:700; color:#fff;
  background:#c0392b; padding:3px 9px; border-radius:999px; }

.app-redesign .tq-meta{ display:flex; flex-wrap:wrap; gap:6px 14px; margin-top:7px; }
.app-redesign .tq-meta span{ display:inline-flex; align-items:center; gap:5px;
  font-size:12.5px; color:var(--text-2); }

.app-redesign .tq-window{ display:flex; gap:9px; margin-top:11px; padding:9px 11px;
  border-radius:10px; background:var(--surface-2,rgba(0,0,0,.04)); font-size:12.5px; }
.app-redesign .tq-window strong{ display:block; font-size:12px; color:var(--text-1); }
.app-redesign .tq-window div div{ color:var(--text-2); }

.app-redesign .tq-note{ margin:10px 0 0; font-size:13px; font-style:italic;
  color:var(--text-2); }

.app-redesign .tq-actions{ display:flex; align-items:center; flex-wrap:wrap;
  gap:10px; margin-top:14px; }
.app-redesign .tq-ago{ margin-left:auto; font-size:11.5px; color:var(--text-3); }
/* Declining is folded away: it refunds a student and is not the common answer,
   so it should take one more deliberate click than approving. */
.app-redesign .tq-decline summary{ cursor:pointer; font-size:12.5px;
  color:var(--text-3); list-style:none; }
.app-redesign .tq-decline summary::-webkit-details-marker{ display:none; }
.app-redesign .tq-decline summary:hover{ color:#c0392b; }
.app-redesign .tq-decline-form{ display:flex; gap:8px; margin-top:9px; flex-wrap:wrap; }
.app-redesign .tq-decline-form input[type=text]{ flex:1 1 220px; }

.app-redesign .tq-empty{ text-align:center; padding:44px 20px; background:var(--white);
  border:1px solid var(--border); border-radius:var(--r-md); margin-top:16px; }
.app-redesign .tq-empty-ic{ display:inline-flex; width:46px; height:46px;
  align-items:center; justify-content:center; border-radius:999px;
  background:var(--surface-2,rgba(0,0,0,.05)); color:var(--text-3); margin-bottom:10px; }
.app-redesign .tq-empty p{ margin:4px 0; }

/* Stack on a phone: a 168px image beside text is unreadable at 390px. */
@media(max-width:620px){
  .app-redesign .tq-card{ flex-direction:column; }
  .app-redesign .tq-media{ flex-basis:auto; height:150px; }
  .app-redesign .tq-media-sm{ height:110px; }
  .app-redesign .tq-ago{ margin-left:0; width:100%; }
}

/* ---------- Plans (agent fee page) — two cards, side by side, one of
   them plainly the paid one. The price is the largest thing in each card
   because it is the only thing being compared; the feature list is
   deliberately short, since a plan nobody finishes reading is a plan
   nobody buys. ---------- */
/* Three plans, three columns. It was two, so the third card dropped to a
   second row on its own and the page looked like it had run out of ideas
   halfway down. Three across while there is width for three; two when there
   is not; one on a phone. */
.app-redesign .plan-grid{ display:grid; gap:16px; margin-top:20px;
  grid-template-columns:repeat(3,minmax(0,1fr)); align-items:stretch; }
.app-redesign .plan-card{ display:flex; flex-direction:column;
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-lg);
  padding:20px 20px 18px; }
/* The paid card gets the ink edge and a lifted shadow — the eye should
   land on it without anything being hidden from the free one. */
.app-redesign .plan-card-pro{ border-color:var(--forest); box-shadow:var(--sh-sm); }
.app-redesign .plan-card-pro .plan-price{ color:var(--forest); }
.app-redesign .plan-price{ font-family:'Cormorant Garamond',serif; font-weight:600;
  font-size:34px; line-height:1.05; margin:0; color:var(--text); }
.app-redesign .plan-price span{ font-family:var(--fb); font-size:13px; font-weight:500;
  color:var(--text-3); margin-left:2px; }
.app-redesign .plan-list{ list-style:none; margin:0 0 16px; padding:0;
  display:flex; flex-direction:column; gap:8px; }
.app-redesign .plan-list li{ display:flex; align-items:flex-start; gap:8px;
  font-size:13.5px; color:var(--text-2); line-height:1.45; }
.app-redesign .plan-list .ic{ flex:none; width:15px; height:15px; margin-top:2px;
  color:var(--lime-dark); }
/* Pushes the button (or the "your plan" note) to the bottom so the two
   cards line up however long the feature lists get. */
.app-redesign .plan-card form{ margin-top:auto; }
.app-redesign .plan-current{ margin:auto 0 0; padding:11px 0; text-align:center;
  font-size:13px; font-weight:600; color:var(--text-3);
  border:1px dashed var(--border-2); border-radius:var(--r-sm); }
@media(max-width:1040px){
  .app-redesign .plan-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media(max-width:620px){
  .app-redesign .plan-grid{ grid-template-columns:minmax(0,1fr); }
}

/* The two halves of Roommates. Underlined tabs rather than buttons: this is a
   place, not an action. */
.rm-tabs{ display:flex; gap:4px; margin:0 0 18px; border-bottom:1px solid var(--border); }
.rm-tab{
  display:inline-flex; align-items:center; gap:8px; padding:11px 16px;
  color:var(--text-2); text-decoration:none; font-weight:600; font-size:14px;
  border-bottom:2px solid transparent; margin-bottom:-1px;
}
.rm-tab .ic{ width:16px; height:16px; }
.rm-tab:hover{ color:var(--text); }
.rm-tab.on{ color:var(--forest); border-bottom-color:var(--lime-dark); }
/* The first tab's label lines up with the heading and the copy under it. Its
   16px of padding is what makes the tap target big enough, but it also pushed
   the text 16px right of everything else on the page, so the row read as
   indented by accident. Only the first — the others are spaced from it.
   This lives here and not in sharing/_style.html because the Roommates half
   that is not a room-share renders these tabs without ever loading that file. */
.rm-tabs .rm-tab:first-child{ padding-left:0; }

/* The contribution ledger on a room-share. Not a payment summary — a
   scoreboard: what is taken, what has actually reached the agent, and what is
   still missing. Nobody is holding this money; the group is tracking it. */
.rm .ledger{
  margin-top:14px; border:1px solid var(--border); border-radius:var(--r-md);
  background:var(--white); overflow:hidden;
}
.rm .ledger-row{
  display:flex; justify-content:space-between; align-items:baseline; gap:18px;
  padding:14px 18px; font-size:14px;
}
.rm .ledger-row + .ledger-row{ border-top:1px solid var(--border); }
.rm .ledger-row span{ color:var(--text-2); }
.rm .ledger-row b{ color:var(--forest); }
.rm .ledger-row.is-quiet b{ color:var(--text-2); font-weight:600; }

/* ==========================================================================
   Phone shell: quick access, a bar with the brand in it, round filters.

   Everything here is inside one max-width:899px block, which is the width at
   which the sidebar stops being a column and becomes a drawer. Below it the
   app is a phone app and gets the furniture a phone app has; above it the
   sidebar carries the navigation and none of this renders.
   ========================================================================== */
/* Both of the phone-only components are hidden at the base and switched on
   inside the one max-width block below. The quick rail had only the rule
   *inside* the media query, so above 900px it had no display of its own and
   fell back to block — the circles rendered under the page heading on every
   desktop, looking like a row of broken links. A component that exists for
   one breakpoint has to say so at both. */
.app-redesign .topbar-brand{ display:none; }
.app-redesign .qrail{ display:none; }
.app-redesign .filters-bar{ display:none; }
.app-redesign .explore-hero-art,
.app-redesign .explore-tag,
.app-redesign .filters-sheet-head,
.app-redesign .filters-backdrop{ display:none; }

/* ---------- Explore: the heading, the search, and the pause --------------
   Desktop keeps the heading as a heading. Everything below is the phone's. */
.app-redesign .explore-head{ margin-bottom:22px; }
.app-redesign .explore-head h1{ font-size:26px; margin:0 0 8px; }
.app-redesign .explore-head .muted{ margin:0; }

/* A real search field, not a select with a magnifying glass on it. It sits
   between the heading and the filters because that is the order of the
   questions: what am I looking for, then narrow it. */
.app-redesign .explore-search{
  display:flex; align-items:center; gap:10px;
  /* Capped rather than full width: a search field spanning 1100px is a
     textarea with a magnifying glass on it, and the eye reads a long empty
     box as somewhere to write a paragraph. */
  max-width:560px;
  background:var(--white); border:1px solid var(--border); border-radius:var(--pill);
  padding:6px 6px 6px 16px; margin:0 0 20px; box-shadow:var(--sh-sm);
}
.app-redesign .explore-search:focus-within{ border-color:var(--lime-dark); }
.app-redesign .es-ic{ display:flex; flex:none; color:var(--text-3); }
.app-redesign .es-ic .ic{ width:18px; height:18px; }
.app-redesign .explore-search input[type=search]{
  flex:1; min-width:0; border:0; background:none; outline:none;
  font-family:'Inter', sans-serif; font-size:15px; color:var(--text);
}
.app-redesign .explore-search input[type=search]::placeholder{ color:var(--text-3); }
.app-redesign .es-go{
  flex:none; width:42px; height:42px; border-radius:50%; border:0; cursor:pointer;
  background:var(--forest); color:var(--on-dark);
  display:flex; align-items:center; justify-content:center;
}
.app-redesign .es-go .ic{ width:18px; height:18px; }
.app-redesign .es-go:hover{ background:var(--forest-600); }

/* ---------- The pause while the results load --------------------------- */
.app-redesign .page-busy{
  position:fixed; inset:0; z-index:200;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px;
  background:rgba(242,238,229,.82); backdrop-filter:blur(2px);
  font-family:'Inter', sans-serif; font-size:14px; color:var(--text-2);
}
.app-redesign .page-busy[hidden]{ display:none; }
.app-redesign .pb-ring{
  width:38px; height:38px; border-radius:50%;
  border:3px solid var(--border-2); border-top-color:var(--forest);
  animation:pb-spin .8s linear infinite;
}
@keyframes pb-spin{ to{ transform:rotate(360deg); } }
@media(prefers-reduced-motion:reduce){
  .app-redesign .pb-ring{ animation-duration:2.4s; }
}

@media(max-width:899px){

  /* ---------- the bar ----------------------------------------------------
     Three things used to fight for one row on a 390px screen: the hamburger,
     the title, and a campus chip with the full university name in it. The
     chip lost last and pushed the notification bell off the right edge, so
     the page scrolled sideways and the bell was half off-screen.

     The chip moves out of the bar entirely — it is a filter, and it belongs
     with the other filters, which is where the picker link already sits on
     Explore. The brand moves in, because that is what the row is for. */
  /* A bar worth looking at. It was 63px with a 30px mark and a 17px title,
     which is a toolbar — everything in it read as an afterthought to the page
     under it. The mark goes to 40px and the title to 20px, and the controls
     grow with them so the row stays one weight instead of a big logo beside
     three small buttons. */
  .app-redesign .topbar{ gap:12px; padding:15px 16px; }
  /* .grow is `flex:1` with no min-width, so a child that cannot wrap sets the
     row's width instead of being clipped by it. With the title now on one
     line that meant the whole document was 443px wide on a 390px screen —
     the fixed tab bar inherited it and the page scrolled sideways. */
  .app-redesign .topbar .grow{ min-width:0; }
  .app-redesign .topbar h1{
    font-size:20px; line-height:1.25;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .app-redesign .topbar-brand{
    display:flex; align-items:center; flex:none;
    width:44px; height:44px; border-radius:var(--r-sm);
    justify-content:center;
  }
  .app-redesign .topbar-brand .mk{ width:40px; height:40px; display:block; }
  .app-redesign .topbar .hamburger{ width:44px; height:44px; flex:none; }
  .app-redesign .topbar .hamburger .ic{ width:24px; height:24px; }
  /* The bell is 40px everywhere else and sits in this row, so it grows here
     too — a 40px circle beside a 44px one reads as the one that was missed. */
  .app-redesign .topbar .notif-btn{ width:44px; height:44px; }
  .app-redesign .topbar .notif-btn .ic{ width:23px; height:23px; }
  /* The actions block is where pages put their own controls. Let it shrink
     and scroll rather than widen the row past the viewport. */
  .app-redesign .topbar > .row{ flex:none; min-width:0; }
  .app-redesign .topbar > .row > *{ flex:none; }

  /* ---------- room at the bottom ----------------------------------------
     The bar is fixed, so the last card would sit under it. --tab-h is the
     height styles.css declares for it; the extra 20px is the breathing space
     the old rule already chose. */
  .app-redesign .shell-body{ padding-bottom:calc(var(--tab-h) + 20px); }

  /* ---------- two bars, one bottom edge ---------------------------------
     The tab bar and the listing's action bar are both `position:fixed` with
     `bottom:0`, and the tab bar wins on z-index (60 against 55). So on a room
     with a priced drone tour the action bar's first row — "See it from the
     air" — stuck out above the tab bar and its second row, Message and Save,
     sat underneath it. Not clipped, not scrollable: covered for good, because
     nothing fixed can be scrolled into view.

     Measured before the fix at 390x844: the action bar ran 700-844, the tab
     bar started at 783, and the button row was 61px underneath it.

     The action bar now stacks above the tab bar, with 14px of air so it also
     clears the raised centre button, which pokes about 12px above the bar's
     own top edge. It keeps the safe-area offset because it is no longer the
     thing touching the bottom of the screen. */
  .app-redesign .actionbar{
    bottom:calc(var(--tab-h) + 14px + env(safe-area-inset-bottom));
    z-index:56;
    padding-bottom:14px;
  }
  /* And the page reserves room for both bars, not only the taller one: 14px
     of padding, a 53px row, 10px of gap, and the 14px the bar is lifted by.
     The old 110/172 were guesses at the action bar's own height and were 28px
     short of it even before the tab bar was counted. */
  .app-redesign .has-actionbar{
    padding-bottom:calc(170px + var(--tab-h) + 14px + env(safe-area-inset-bottom));
  }
  .app-redesign .has-actionbar-tall{
    padding-bottom:calc(230px + var(--tab-h) + 14px + env(safe-area-inset-bottom));
  }

  /* ---------- quick access ---------------------------------------------- */
  .app-redesign .tabbar{
    align-items:flex-start; padding:8px 6px calc(6px + env(safe-area-inset-bottom));
    background:var(--white); border-top:1px solid var(--border);
    box-shadow:0 -6px 22px -14px rgba(23,21,18,.5);
  }
  .app-redesign .tabbar .tb-item{
    display:flex; flex-direction:column; align-items:center; gap:3px;
    flex:1; min-width:0; padding:5px 2px 0;
    color:var(--text-3); font-size:10.5px; font-weight:600;
    letter-spacing:.01em; text-decoration:none;
    /* A tab is a tap target first and a label second. */
    min-height:46px; justify-content:flex-start;
  }
  .app-redesign .tabbar .tb-item .ic{ width:22px; height:22px; }
  .app-redesign .tabbar .tb-item span{
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .app-redesign .tabbar .tb-item.on{ color:var(--forest); }
  .app-redesign .tabbar .tb-dot{
    position:absolute; margin:-30px 0 0 16px;
    min-width:16px; height:16px; padding:0 4px; border-radius:999px;
    background:var(--danger); color:#fff; font-size:9.5px; font-weight:700;
    display:flex; align-items:center; justify-content:center;
  }

  /* The middle slot. Raised, filled, and the only round thing in the bar —
     the platform look people already read as "this is where you post". */
  .app-redesign .tabbar .tb-fab{
    flex:0 0 auto; width:54px; height:54px; margin:-20px 6px 0;
    border-radius:50%; background:var(--forest); color:var(--on-dark);
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:1px; text-decoration:none;
    box-shadow:0 8px 20px -8px rgba(23,21,18,.7), 0 0 0 5px var(--white);
  }
  .app-redesign .tabbar .tb-fab .ic{ width:24px; height:24px; }
  .app-redesign .tabbar .tb-fab-label{ font-size:9px; font-weight:700; letter-spacing:.02em; }
  .app-redesign .tabbar .tb-fab.on{ background:var(--forest-600); }
  /* Locked, not hidden: an unverified agent still needs to reach the page
     that says why. Muted rather than removed, so the bar keeps its shape. */
  .app-redesign .tabbar .tb-fab.is-locked{ background:var(--text-3); opacity:.75; }

  /* ---------- round quick filters ---------------------------------------
     The rail is the page's own filter set, not the poster's: self-contain,
     single room, room & parlour, shared. Four types and "All", which is all
     that fits across a phone, so it does not scroll and the row you see is
     the whole set. The negative margins let it run to both screen edges while
     the first chip still lines up with the text above it. */
  .app-redesign .qrail{
    display:flex; gap:6px; align-items:flex-start;
    margin:0 -18px 16px; padding:2px 18px 4px;
  }
  .app-redesign .qchip{
    flex:0 0 auto; width:76px;
    display:flex; flex-direction:column; align-items:center; gap:7px;
    text-decoration:none; padding:2px 0; border-radius:var(--r-md);
  }
  .app-redesign .qchip-ic{
    width:56px; height:56px; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    background:var(--white); border:1px solid var(--border);
    color:var(--forest); transition:background .15s ease, color .15s ease, border-color .15s ease;
  }
  .app-redesign .qchip-ic .ic{ width:23px; height:23px; }
  .app-redesign .qchip-label{
    font-size:11px; font-weight:600; color:var(--text-2);
    text-align:center; line-height:1.25; max-width:100%;
  }
  /* Chosen: the guideline's signal green, filled, with the label going to
     full ink so the pair reads as one control rather than a dot and a word. */
  .app-redesign .qchip.on .qchip-ic{
    background:var(--lime-pop); border-color:var(--lime-pop-deep); color:var(--on-lime);
    box-shadow:0 4px 12px -6px rgba(154,196,31,.9);
  }
  .app-redesign .qchip.on .qchip-label{ color:var(--text); font-weight:700; }
  .app-redesign .qchip:active .qchip-ic{ transform:scale(.95); }
  .app-redesign .qchip:focus-visible{ outline:2px solid var(--lime-pop-deep); outline-offset:2px; }

  /* ---------- cards ------------------------------------------------------
     Three lines of description on a 390px screen is the whole card before the
     price. The description is what the detail page is for. */
  .app-redesign .property-description{ display:none; }
  .app-redesign .listings-grid{ gap:16px; }
  .app-redesign .content-area{ padding:16px 18px 0; }
}


@media(prefers-reduced-motion:reduce){
  .app-redesign .qchip-ic{ transition:none; }
}

/* The campus chip: in the topbar above 900px, in the filters row below it.
   Two copies in the markup because there is no way to move a node between
   containers with CSS, and a chip that renders once and jumps is worth one
   duplicate. */
@media(max-width:899px){
  .app-redesign .chip-in-bar{ display:none; }
  /* The chip takes everything the Filters button leaves, so the pair spans the
     row the way the sort controls underneath span theirs. min-width:0 is what
     lets it actually shrink; without it the chip's own text sets a floor and
     the row overflows instead. */
  .app-redesign .chip-in-filters{ flex:1 1 auto; min-width:0; display:flex; }
  .app-redesign .chip-in-filters .campus-chip{ width:100%; }
}

/* The select rail, uncarded, on phones.

   It was already a horizontal scroller down here, but it kept the white card
   and its 24px of padding, so the second control was sliced off at the card's
   inner edge with no hint that it moved. A cut-off field does not read as
   "swipe me", it reads as a layout that broke — and it was the first thing
   under the quick filters, which are the same idea done properly.

   So the card goes and the rail runs to both screen edges like the circles
   above it. The edge fade the rail already applies while it overflows is what
   says there is more sideways; the card was only ever there to say "these
   belong together", and their position under one another says that already. */
@media(max-width:899px){
  .app-redesign .filters-section{
    background:none; border:0; box-shadow:none; border-radius:0;
    padding:0; margin:0 -18px 20px;
  }
  .app-redesign .filters-container{
    padding:0 18px 2px; margin:0; gap:10px;
  }
  .app-redesign .filter-group{ flex:0 0 auto; width:min(58vw, 190px); }
  .app-redesign .filter-group label{ font-size:11.5px; }
  .app-redesign .filter-group select,
  .app-redesign .filter-group input{ font-size:16px; padding:11px 13px; }
  .app-redesign .filter-actions{ gap:8px; }
  .app-redesign .apply-filters,
  .app-redesign .reset-filters{ padding:11px 18px; font-size:14px; }
}

/* The quick rail gets the same edge fade the select rail already had, for the
   same reason: a circle cut off at the screen edge is how a phone says "there
   is more this way", and without the fade it just looks like the last one did
   not fit. Applied to both edges so it also says there is more behind you. */
.app-redesign .qrail.is-scrollable.fade-end{
  -webkit-mask-image:linear-gradient(to right, #000 0, #000 calc(100% - 34px), transparent 100%);
          mask-image:linear-gradient(to right, #000 0, #000 calc(100% - 34px), transparent 100%);
}
.app-redesign .qrail.is-scrollable.fade-start{
  -webkit-mask-image:linear-gradient(to right, transparent 0, #000 34px);
          mask-image:linear-gradient(to right, transparent 0, #000 34px);
}
.app-redesign .qrail.is-scrollable.fade-start.fade-end{
  -webkit-mask-image:linear-gradient(to right, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%);
          mask-image:linear-gradient(to right, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%);
}

/* The bar's primary button, handed over to the tab bar on phones.

   Five pages put their one main action up here — "Find a room", "New listing",
   "Start a group" — and every one of them is now the centre button of the tab
   bar, which is a shorter reach and always in the same place. Left in both,
   the two compete for a 390px row and the page title loses: the dashboard's
   heading was down to "Das…" before this.

   Only .btn-primary, deliberately. The notifications page's "Mark all read"
   is a ghost button and the listing page's share control is its own thing;
   neither has a tab bar equivalent, and hiding them would remove a control
   rather than move it. */
@media(max-width:899px){
  .app-redesign .topbar .btn-primary{ display:none; }
}

/* ==========================================================================
   Explore on a phone: a hero, room to breathe, and the filters behind a door.

   Three horizontal scrollers used to stack above the first listing — the
   circles, the five selects, and the sort row — and the screenshot that came
   back from a real handset showed exactly what that is: five controls, four
   of them off the right edge, between the visitor and the first room. The
   circles stay because one tap for the common types is worth a row. The form
   moves into a sheet, where there is room to show all of it at once.
   ========================================================================== */
@media(max-width:899px){

  /* ---------- breathing room ------------------------------------------- */
  .app-redesign .content-area{ padding:16px 18px 0; }
  /* Explore only. The hero bleeds to both side edges already, so the top
     padding was the one edge still showing the page background above it. */
  .app-redesign .content-area--flush{ padding-top:0; }
  .app-redesign .listings-grid{ gap:16px; }

  /* ---------- the hero --------------------------------------------------
     It was 186px, which is a band: enough to say "rooms", not enough to see
     one — and these are real flats rather than a stock bedroom, which is the
     only reason to lead with a photograph at all. It went to 372 and has come
     back 10% to 335, which is still most of the picture and a little less
     scrolling before the first room.

     The copy is centred rather than sitting on the foot of the image. On the
     foot it needed the scrim to fade almost to black behind it, and the
     heading and the tag ended up crowded into the last fifth of the frame
     with a strip of dead photograph above them. Centred, the copy occupies
     the middle of the picture and the darkening can be a gradient across the
     whole thing instead of a lid. */
  .app-redesign .explore-head{
    position:relative; margin:0 -18px 18px; min-height:335px;
    display:flex; align-items:center;
    overflow:hidden;
  }
  .app-redesign .explore-hero-art{ display:block; position:absolute; inset:0; }
  .app-redesign .explore-hero-art img{
    width:100%; height:100%; object-fit:cover; display:block;
  }
  /* The scrim follows the copy, and the copy is in the middle now.

     It used to run dark-to-black towards the foot because that is where the
     heading sat; centred, that put the heaviest part of the wash under an
     empty strip of photograph and left the heading at .58 over a white bunk
     bed. It is a band instead: light at the top so the picture still reads as
     a picture, a steady .70 across the band the copy actually occupies, and
     lighter again at the foot, where the search field lands on top of it. */
  .app-redesign .explore-hero-art::after{
    content:''; position:absolute; inset:0;
    background:linear-gradient(180deg,
      rgba(20,24,16,.45) 0%, rgba(20,24,16,.70) 25%,
      rgba(20,24,16,.70) 78%, rgba(20,24,16,.50) 100%);
  }
  /* Symmetric, because the block is centred: 20 top and 22 bottom was two
     pixels of lean that nobody could name and everybody could see. */
  .app-redesign .explore-hero-copy{ position:relative; padding:26px 18px; }
  .app-redesign .explore-tag{
    display:inline-flex; align-items:center; gap:6px;
    background:var(--lime-pop); color:var(--on-lime);
    font-family:'Inter', sans-serif; font-size:10.5px; font-weight:700;
    letter-spacing:.07em; text-transform:uppercase;
    padding:5px 11px; border-radius:var(--pill); margin-bottom:14px;
  }
  .app-redesign .explore-tag .ic{ width:13px; height:13px; }
  .app-redesign .explore-head h1{
    font-family:'Cormorant Garamond', serif; font-weight:500;
    /* 26 rather than 30: at 30 the heading ran to three lines and the hero
       took a third of the screen before a single room was in view. */
    font-size:26px; line-height:1.16; letter-spacing:-.01em;
    color:#fff; margin:0 0 12px; max-width:20ch;
  }
  .app-redesign .explore-head .muted{
    color:rgba(255,255,255,.82); font-size:13.5px; line-height:1.5;
    margin:0; max-width:34ch;
  }

  /* Tucked up into the hero's foot so the two read as one card. */
  .app-redesign .explore-search{
    margin:-30px 18px 20px; position:relative; z-index:2;
    padding-left:14px; box-shadow:0 10px 24px -14px rgba(20,24,16,.6);
  }

  /* ---------- the filters door ----------------------------------------- */
  .app-redesign .filters-bar{
    display:flex; align-items:center; gap:12px; margin:0 0 16px;
  }
  .app-redesign .filters-open{
    display:inline-flex; align-items:center; gap:8px;
    padding:11px 18px; border-radius:var(--pill); cursor:pointer;
    background:var(--white); border:1px solid var(--border-2); color:var(--text);
    font-family:'Inter', sans-serif; font-size:14px; font-weight:600;
  }
  .app-redesign .filters-open .ic{ width:17px; height:17px; color:var(--forest); }
  .app-redesign .filters-open:active{ transform:scale(.97); }
  .app-redesign .fo-n{
    min-width:19px; height:19px; padding:0 5px; border-radius:999px;
    background:var(--lime-pop); color:var(--on-lime);
    font-size:11px; font-weight:700;
    display:inline-flex; align-items:center; justify-content:center;
  }
  /* The count line and the sort controls were a crowded row, so the count was
     moved up beside the Filters button and the controls got the row. It has
     moved back down here, and up there it was competing with the campus name
     for the same 354px — "Filters", the chip and the count need 391 between
     them, and the only one of the three that can give way is the name that
     must not be truncated. Down here it has the row to itself and sits where
     the cards are, which is where a count is worth reading. */
  .app-redesign .listings-header{ display:block; margin-bottom:14px; }
  .app-redesign .listings-count{
    display:block; font-size:13px; color:var(--text-2); margin:0 0 8px;
  }
  .app-redesign .listings-tools{ gap:10px; }

  /* ---------- the sheet ------------------------------------------------- */
  .app-redesign .filters-backdrop{
    display:block; position:fixed; inset:0; z-index:150;
    background:rgba(20,24,16,.5);
    opacity:0; transition:opacity .2s ease;
  }
  .app-redesign .filters-backdrop[hidden]{ display:none; }
  .app-redesign .filters-backdrop.is-open{ opacity:1; }

  .app-redesign .filters-section{
    position:fixed; left:0; right:0; bottom:0; z-index:160;
    margin:0; padding:0;
    max-height:88vh; overflow-y:auto;
    background:var(--white);
    border:0; border-radius:var(--r-xl) var(--r-xl) 0 0;
    box-shadow:0 -14px 40px -18px rgba(20,24,16,.7);
    transform:translateY(102%);
    transition:transform .26s cubic-bezier(.2,.8,.3,1);
    padding-bottom:calc(18px + env(safe-area-inset-bottom));
  }
  .app-redesign .filters-section.is-open{ transform:none; }
  /* Anything taller than the sheet scrolls inside it, so the Apply button
     stays reachable without scrolling the page behind. */
  .app-redesign .filters-sheet-head{
    display:flex; align-items:center; justify-content:space-between;
    position:sticky; top:0; z-index:1;
    padding:16px 18px 12px; background:var(--white);
    border-bottom:1px solid var(--border);
  }
  .app-redesign .fs-title{
    display:inline-flex; align-items:center; gap:8px;
    font-family:'Inter', sans-serif; font-size:16px; font-weight:700; color:var(--text);
  }
  .app-redesign .fs-title .ic{ width:18px; height:18px; color:var(--forest); }
  .app-redesign .fs-close{
    width:36px; height:36px; border-radius:50%; cursor:pointer;
    border:1px solid var(--border); background:var(--surface-alt); color:var(--text-2);
    display:flex; align-items:center; justify-content:center;
  }
  .app-redesign .fs-close .ic{ width:16px; height:16px; }

  /* One column, full width, with a finger's width between the fields. The
     rail becomes a stack — sideways scrolling made sense in a bar that had no
     room; this has room. */
  .app-redesign .filters-container{
    flex-direction:column; flex-wrap:nowrap; gap:18px;
    padding:18px 18px 4px; margin:0; overflow:visible;
    -webkit-mask-image:none; mask-image:none;
  }
  .app-redesign .filter-group{ width:100%; flex:0 0 auto; gap:9px; }
  .app-redesign .filter-group label{ font-size:13px; }
  .app-redesign .filter-group select,
  .app-redesign .filter-group input{ width:100%; font-size:16px; padding:14px; }
  .app-redesign .filter-actions{
    position:sticky; bottom:0;
    flex-direction:column-reverse; gap:10px; margin:0;
    padding:14px 18px calc(4px + env(safe-area-inset-bottom));
    background:linear-gradient(180deg, rgba(248,246,239,0) 0%, var(--white) 22%);
  }
  .app-redesign .apply-filters,
  .app-redesign .reset-filters{
    width:100%; text-align:center; padding:15px 20px; font-size:15px;
    display:inline-flex; align-items:center; justify-content:center; gap:8px;
  }
  .app-redesign .apply-filters .ic{ width:17px; height:17px; }

  /* ---------- the cards get their room back ---------------------------- */
  .app-redesign .property-title{ font-size:17px; line-height:1.3; }
  .app-redesign .property-features{ gap:8px; }
  .app-redesign .property-footer{ gap:10px; }

  /* Keep the last card clear of the tab bar *and* the sort row. */
  .app-redesign .shell-body{ padding-bottom:calc(var(--tab-h) + 28px); }
}

/* The last of the phone's vertical budget.

   With the hero in place the stack above the first room ran to about 340px on
   a 844px screen — hero, search, campus chip, circles, Filters row, sort row —
   so the thing the page exists for started below the fold. Nothing here is
   removed; three of them are just made to take the room they need. */
@media(max-width:899px){
  /* Two lines instead of three. The heading is still the page's own and still
     in the document; it is only set smaller. */
  .app-redesign .explore-head h1{ font-size:23px; max-width:24ch; }
  .app-redesign .explore-head .muted{ font-size:13px; max-width:38ch; }
  .app-redesign .explore-head{ min-height:335px; margin-bottom:14px; }
  .app-redesign .explore-search{ margin:-28px 18px 14px; }

  /* The chip was a full-width block with "CHANGE UNIVERSITY" over the name
     and a swap icon at the far end: three pieces of furniture for one fact.
     On a phone it becomes what it is — a pill that says which market you are
     in and can be tapped to change. */
  .app-redesign .chip-in-filters .campus-chip{
    width:100%; max-width:100%; padding:5px 11px 5px 10px; gap:7px;
  }
  .app-redesign .chip-in-filters .cc-label{ display:none; }
  .app-redesign .chip-in-filters .cc-value{
    font-size:12.5px; font-weight:600; color:var(--text);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  /* The swap arrow comes back, at the far end of the pill.

     It was hidden along with the "CHANGE UNIVERSITY" label because the chip
     had no width to spare. It has plenty now — the pill takes whatever the
     Filters button leaves, and the name uses 136 of those 237 pixels — and a
     pill with its text bunched at one end and an empty half looks like a
     control that failed to finish loading. The arrow fills it and says what
     the chip does, which is the one thing the name alone does not. */
  .app-redesign .chip-in-filters .cc-swap{ display:inline-flex; margin-left:auto; }

  /* The circles keep their one tap; they give up 4px of diameter and the
     label gutter under them.

     Five of them, and five is now a guarantee rather than a hope: the rail no
     longer scrolls. It was a scroller with six types in it, which put the
     sixth circle — and with it the idea that there were more — off the right
     edge where nobody looks. There are four types plus "All" now, and they
     share the row between them, so what you see is the whole set. */
  .app-redesign .qrail{
    margin:0 -18px 8px; padding:2px 18px 2px; gap:4px; overflow:visible;
  }
  .app-redesign .qchip{ flex:1 1 0; min-width:0; width:auto; gap:5px; }
  .app-redesign .qchip-ic{ width:50px; height:50px; }
  .app-redesign .qchip-ic .ic{ width:21px; height:21px; }
  .app-redesign .qchip-label{ font-size:10.5px; }

  .app-redesign .filters-bar{ margin-bottom:12px; }
  .app-redesign .listings-header{ margin-bottom:12px; }
}

/* The 120px cap on the campus name was written for the topbar, where the chip
   competed with the notification bell for a 390px row. It has a row of its
   own down here — the chip moved into the body precisely so it would — so the
   cap only truncated "Lagos State University" to "Lagos State Univ…" with
   190px of empty space beside it. */
@media(max-width:520px){
  .app-redesign .chip-in-filters .cc-value{ max-width:100%; }
}

/* The narrowest phones still in use: 320px, where the row is 284 and the
   Filters button and the chip have to share it. The chip wants 202px to show
   "Lagos State University" whole and gets 167, and the name is the one part of
   this row that must not be cut — so the arrow goes, the chip's padding and
   gap tighten, and the button gives up 5px a side. That is 177px for the chip
   against the 174 it needs. Nothing here changes at 360px and up. */
@media(max-width:359px){
  .app-redesign .chip-in-filters .cc-swap{ display:none; }
  .app-redesign .chip-in-filters .campus-chip{ padding:5px 9px 5px 8px; gap:6px; }
  .app-redesign .chip-in-filters .cc-value{ font-size:12px; }
  .app-redesign .filters-open{ padding:11px 13px; }
}

/* The sidebar's two account doors, for a visitor.

   They were a filled pill and a bare line of text, which is not a hierarchy —
   it is one button and one thing that looks like it fell out of the layout.
   Both are the same width, the same height and the same pill now; only the
   fill tells them apart. */
.app-redesign .sidebar .sauth{ display:flex; flex-direction:column; gap:10px; }
.app-redesign .sidebar .sauth a{
  display:flex; align-items:center; justify-content:center; gap:9px;
  width:100%; min-height:46px; padding:12px 16px;
  border:1px solid transparent; border-radius:var(--pill); text-decoration:none;
  font-family:'Inter', sans-serif; font-weight:600; font-size:14px;
  transition:background .18s ease, border-color .18s ease;
}
.app-redesign .sidebar .sauth .ic{ width:18px; height:18px; flex:none; }
.app-redesign .sidebar .sauth .sa-primary{ background:var(--on-dark); color:var(--forest); }
.app-redesign .sidebar .sauth .sa-primary:hover{ background:#fff; }
.app-redesign .sidebar .sauth .sa-secondary{
  background:rgba(242,238,229,.10); color:var(--on-dark);
  border-color:rgba(242,238,229,.22);
}
.app-redesign .sidebar .sauth .sa-secondary:hover{ background:rgba(242,238,229,.18); }

/* ---------- the preferences banner on the student dashboard ---------------
   Three elements with nothing between them — the heading sat on the sentence
   and the sentence sat on the button — inside a card as wide as the page.
   Spacing first, then the row at the width where there is room for one. */
.app-redesign .prefs-cta{ margin-top:24px; }
.app-redesign .prefs-copy h2{
  font-family:'Cormorant Garamond', serif; font-weight:500;
  font-size:19px; line-height:1.25; color:var(--text); margin:0 0 6px;
}
/* A readable measure. Left unconstrained it was a single 1054px line, which
   is further than the eye comfortably travels back. */
.app-redesign .prefs-copy p{ margin:0; max-width:54ch; }
.app-redesign .prefs-card .btn{ margin-top:18px; }

@media(min-width:720px){
  .app-redesign .prefs-card{
    display:flex; align-items:center; justify-content:space-between; gap:32px;
  }
  /* The row is the button's line now, so the stacked margin would push it
     off the centre it is meant to sit on. */
  .app-redesign .prefs-card .btn{ margin-top:0; flex:none; }
}

/* ---------- the restricted banner -----------------------------------------
   The partial was written with class names and no rules to go with them, so
   it rendered as a bare block: a lock icon, a bold line, one 1100px sentence
   and two buttons, edge to edge on the page background with nothing to say
   where the notice stopped and the dashboard started. It read as leftover
   text rather than as a status.

   It is a card now, with the icon in its own tinted tile so the eye lands on
   the state before the sentence, and the sentence capped at a readable
   measure instead of running the width of a laptop. */
.app-redesign .restricted{
  display:flex; align-items:flex-start; gap:14px;
  padding:18px 20px; margin:0 0 22px;
  background:var(--white);
  border:1px solid var(--border);
  border-left:3px solid var(--warning);
  border-radius:var(--r-lg);
  box-shadow:var(--sh-sm, 0 1px 2px rgba(23,21,18,.04));
}
.app-redesign .restricted-ic{
  display:flex; align-items:center; justify-content:center; flex:none;
  width:38px; height:38px; border-radius:var(--r-sm);
  background:#f6efe3; color:var(--warning);
}
.app-redesign .restricted-ic .ic{ width:19px; height:19px; }
/* Without this the flex item is sized by its content, so the paragraph sets
   the row's width instead of wrapping inside it. Same trap the topbar hit. */
.app-redesign .restricted .grow{ min-width:0; }
.app-redesign .restricted strong{
  display:block; font-size:15px; line-height:1.35; color:var(--text);
}
.app-redesign .restricted p{
  max-width:62ch; font-size:13.5px; line-height:1.55; color:var(--text-2);
}
.app-redesign .restricted .btn{ white-space:nowrap; }

@media(max-width:520px){
  /* The icon tile costs 52px of a 354px row and the sentence has nowhere to
     go. The state is already in the bold line, so the tile goes. */
  .app-redesign .restricted{ padding:15px 16px; gap:0; }
  .app-redesign .restricted-ic{ display:none; }
}

/* ---------- where the free preview ends -----------------------------------
   Shown to a visitor with no account who asked for a second page. Same card
   as the restricted banner, because it is the same kind of thing: a limit
   the site is telling them about, with the way past it attached. */
.app-redesign .preview-end{
  display:flex; align-items:flex-start; gap:14px;
  margin:26px 0 0; padding:18px 20px;
  background:var(--white); border:1px solid var(--border);
  border-left:3px solid var(--lime-pop-deep);
  border-radius:var(--r-lg);
}
.app-redesign .preview-end-ic{
  display:flex; align-items:center; justify-content:center; flex:none;
  width:38px; height:38px; border-radius:var(--r-sm);
  background:#f2f7e4; color:var(--lime-dark);
}
.app-redesign .preview-end-ic .ic{ width:19px; height:19px; }
.app-redesign .preview-end strong{ display:block; font-size:15px; color:var(--text); }
.app-redesign .preview-end p{ max-width:62ch; line-height:1.55; }

@media(max-width:520px){
  .app-redesign .preview-end{ padding:15px 16px; }
  .app-redesign .preview-end-ic{ display:none; }
}

/* ---------- a filter this tier does not have ------------------------------
   Drawn rather than removed. A filter nobody can see is a filter nobody knows
   exists, and the door this one points at is the point of the whole page. */
.app-redesign .filter-locked{
  display:flex; align-items:center; gap:8px;
  padding:11px 14px; border-radius:var(--r-md);
  background:var(--surface-alt); border:1px dashed var(--border-2);
  color:var(--text-2); font-size:13.5px; text-decoration:none;
}
.app-redesign .filter-locked .ic{ width:15px; height:15px; flex:none; color:var(--warning); }
.app-redesign .filter-locked:hover{ border-color:var(--lime-dark); color:var(--text); }
