/* ==========================================================================
   Internship Bazaar — Header, footer, and page layouts
   ========================================================================== */

/* ---------- Header ------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 90;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
}
@supports not (backdrop-filter: blur(1px)) { .site-header { background: var(--bg); } }

.nav {
  /* Three tracks — brand | nav links | actions — each 1fr on the outer two
     so the middle column sits at the true horizontal center of the header,
     not just "after the logo". A flex row with margin-left:auto on the
     actions only centers the links if the brand and actions happen to be
     the same width, which they aren't here (actions has several icon
     buttons + avatar, brand is just the logo) — that mismatch was pushing
     the nav links visibly off-center toward the left. */
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 1rem;
  height: var(--nav-h); max-width: var(--container-wide);
  margin-inline: auto; padding-inline: 1.25rem;
}
.brand { display: flex; align-items: center; gap: .6rem; font-weight: 800; color: var(--text); font-size: 1.05rem; letter-spacing: -.03em; }
@media (hover: hover) { .brand:hover { text-decoration: none; } }
/* Sized against --nav-h (68px), not picked in the abstract: this logo is a
   two-line stacked wordmark next to the mark, so each line only gets half
   the height — it needs noticeably more room than a single-line wordmark
   would to stay readable. ~46px leaves a comfortable margin in a 68px bar. */
.brand-logo { height: 2.9rem; width: auto; display: block; flex: none; }
/* The logo's wordmark is dark grey — invisible against a dark background.
   A full white silhouette (common practice for a reversed logo mark on
   dark surfaces) reads reliably instead of shipping a second logo file. */
:root[data-theme="dark"] .brand-logo { filter: brightness(0) invert(1); }

.nav-links { display: flex; align-items: center; gap: .15rem; }
.nav-link {
  padding: .5rem .75rem; border-radius: var(--r-md); font-weight: 600;
  color: var(--text-muted); font-size: var(--fs-base);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
@media (hover: hover) { .nav-link:hover { background: var(--surface-hover); color: var(--text); text-decoration: none; } }
.nav-link[aria-current="page"] { color: var(--primary); background: var(--primary-soft); }

.nav-actions { display: flex; align-items: center; gap: .5rem; justify-self: end; }

.bell { position: relative; }
.bell-dot {
  position: absolute; top: .32rem; right: .32rem; min-width: 1.05rem; height: 1.05rem;
  padding: 0 .22rem; border-radius: var(--r-full); background: var(--red-500); color: #fff;
  font-size: .625rem; font-weight: 800; display: grid; place-items: center;
  border: 2px solid var(--bg);
}

/* ---------- Employer dashboard chrome -------------------------------------
 * Only rendered by components/header.js while signed in as an employer and
 * viewing /employer* — every other route keeps the standard .nav above,
 * untouched. Two tracks, not the standard .nav's three: with no search box
 * (or nav-links) in the middle, "auto 1fr" pins the brand left and the
 * actions hard right — same fix as .nav's own mobile rule just below, for
 * the same reason (a middle "auto" track with nothing in it would otherwise
 * pull .nav-actions to the horizontal center instead of the right edge). */
.emp-nav { grid-template-columns: auto 1fr auto; }
.emp-links { justify-content: center; }
.emp-account { display: flex; align-items: center; gap: .5rem; }
.emp-account-name { font-weight: 600; font-size: var(--fs-sm); max-width: 10rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.menu {
  position: absolute; top: calc(100% + .5rem); right: 0; z-index: 95;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg); min-width: 15rem; padding: .4rem;
  animation: modal-in .18s var(--ease-out);
  /* A .menu that scrolls (the city picker, notifications, Sort/status
     dropdowns) has no visible track cutting into its rounded corners —
     that's the site-wide rule in styles.css now, not repeated here. */
}
.menu-wide { min-width: 22rem; max-height: 26rem; overflow-y: auto; }
.menu-item {
  display: flex; align-items: center; gap: .6rem; width: 100%; text-align: left;
  padding: .55rem .7rem; border-radius: var(--r-md); border: 0; background: none;
  color: var(--text); font-weight: 600; font-size: var(--fs-base); cursor: pointer;
}
@media (hover: hover) { .menu-item:hover { background: var(--surface-hover); text-decoration: none; } }
.menu-item.danger { color: var(--red-500); }
.menu-head { padding: .6rem .7rem .4rem; font-size: var(--fs-xs); font-weight: 800;
  text-transform: uppercase; letter-spacing: .07em; color: var(--text-subtle); }
.menu-sep { height: 1px; background: var(--border); margin: .35rem 0; }
.has-menu { position: relative; }

/* Account dropdown's own header — real photo/initials + name + email,
   replacing a bare email address stretched across the all-caps .menu-head
   label style meant for short section titles, not identity info. */
.menu-account-head { display: flex; align-items: center; gap: .65rem; padding: .3rem .5rem .7rem; }
.menu-account-name { font-weight: 800; font-size: var(--fs-sm); color: var(--text); line-height: 1.3; }
.menu-account-email {
  font-size: var(--fs-xs); color: var(--text-subtle); line-height: 1.3; margin-top: .1rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.notif-item { display: flex; gap: .7rem; padding: .7rem; border-radius: var(--r-md); }
@media (hover: hover) { .notif-item:hover { background: var(--surface-hover); text-decoration: none; } }
.notif-item.unread { background: var(--primary-soft); }
.notif-item .dot { width: .5rem; height: .5rem; border-radius: 50%; background: var(--primary); margin-top: .45rem; flex: none; }

/* Mobile nav */
.nav-toggle { display: none; }
/* The drawer stays in the page and is shown or hidden by .is-open, rather
   than being inserted when opened and removed when closed. Removal was
   instant, so only opening could ever animate; with the element kept, both
   directions run the same slide-and-fade. visibility (not display) is what
   takes a closed drawer out of the tab order and away from screen readers,
   and its transition is delayed on close so the fade finishes first. */
.mobile-drawer {
  position: fixed; inset: var(--nav-h) 0 0; z-index: 88; background: var(--bg);
  padding: 1.25rem; overflow-y: auto;
  opacity: 0; transform: translateY(-.75rem); visibility: hidden; pointer-events: none;
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility 0s linear .22s;
}
.mobile-drawer.is-open {
  opacity: 1; transform: none; visibility: visible; pointer-events: auto;
  transition: opacity .24s var(--ease-out), transform .24s var(--ease-out), visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
  .mobile-drawer, .mobile-drawer.is-open { transition: none; transform: none; }
}
.mobile-drawer .nav-link { display: block; padding: .85rem .75rem; font-size: var(--fs-lg); }

/* ---------- Footer ------------------------------------------------------- */
.site-footer { background: var(--bg-subtle); border-top: 1px solid var(--border); padding-block: 3.5rem 2rem; margin-top: 4rem; }
.footer-grid { display: grid; grid-template-columns: 1.4fr .8fr 2fr 1.6fr; gap: 2.5rem; }
.footer-col h4 { font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: .07em; color: var(--text-subtle); margin-bottom: .9rem; }
.footer-col ul { list-style: none; padding: 0; display: grid; gap: .55rem; }
.footer-col a { color: var(--text-muted); font-weight: 500; }
@media (hover: hover) { .footer-col a:hover { color: var(--primary); } }
/* The full category list flows into two columns so a long list stays short on the page. */
.footer-col ul.footer-cats { display: block; column-count: 2; column-gap: 1.75rem; }
.footer-cats li { break-inside: avoid; margin-bottom: .55rem; }
.footer-bottom {
  margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border);
  display: flex; gap: 1rem; justify-content: space-between; flex-wrap: wrap;
  color: var(--text-subtle); font-size: var(--fs-sm);
}
/* The "Contact" entry opens a modal (footer.js), not a link — reset to
   look exactly like the Terms/Privacy links either side of it. */
.footer-link-btn {
  border: 0; background: none; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer;
}
@media (hover: hover) { .footer-link-btn:hover { text-decoration: underline; } }

/* ---------- Hero --------------------------------------------------------- */
.hero { position: relative; overflow: hidden; padding-block: clamp(3rem, 7vw, 6rem) clamp(2.5rem, 5vw, 4rem); }
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(60rem 32rem at 12% -10%, var(--primary-soft), transparent 60%),
    radial-gradient(46rem 26rem at 92% 8%, var(--accent-soft), transparent 62%);
}
.hero-grid { display: grid; grid-template-columns: 1.15fr .85fr; gap: 3rem; align-items: center; }
.hero h1 { font-size: clamp(2.1rem, 5.2vw, 3.5rem); letter-spacing: -.035em; }
.hero h1 .accent {
  background: linear-gradient(120deg, var(--teal-500), var(--teal-700) 60%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
:root[data-theme="dark"] .hero h1 .accent { background: linear-gradient(120deg, var(--teal-300), var(--teal-400)); -webkit-background-clip: text; background-clip: text; }
.hero-sub { font-size: clamp(1rem, 1.7vw, 1.2rem); color: var(--text-muted); margin-top: 1rem; max-width: 34rem; }
.hero-trust { display: flex; gap: 1.5rem; flex-wrap: wrap; margin-top: 1.75rem; }
.trust-item { display: flex; align-items: center; gap: .5rem; font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted); }
.trust-item svg { color: var(--primary); flex: none; }

/* Hero search */
.searchbar {
  display: grid; grid-template-columns: 1.4fr 1fr auto; gap: .5rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: .5rem; box-shadow: var(--shadow-lg); margin-top: 2rem;
}
.searchbar .sb-field { display: flex; align-items: center; gap: .55rem; padding: .3rem .75rem; border-radius: var(--r-lg); }
.searchbar .sb-field:focus-within { background: var(--bg-subtle); }
/* The tint above was the only focus signal, and at 1.06:1 against the white
   card it could not be seen - a focus indicator needs 3:1. The inset ring
   in --primary is what actually shows; the tint stays as a softer second
   cue. Text field only: the location field holds a <button> that draws its
   own :focus-visible outline, and a ring around that would double it up. */
.searchbar .sb-field:not(.sb-loc-field):focus-within { box-shadow: inset 0 0 0 2px var(--primary); }
.searchbar .sb-field svg { color: var(--text-subtle); flex: none; }
.searchbar input, .searchbar select {
  border: 0; background: none; padding: .45rem 0; width: 100%; font-weight: 500;
}
.searchbar input:focus, .searchbar select:focus { outline: none; }
.searchbar .sb-sep { width: 1px; background: var(--border); margin-block: .5rem; }

/* Location — themed dropdown replacing the old <select>, whose open popup
   is painted by the OS and can never pick up the site's own styling (see
   the profile page's City field for the same fix, same reasoning). */
.sb-loc-field { position: relative; }
.sb-loc-toggle {
  border: 0; background: none; padding: .45rem 0; width: 100%; font-weight: 500;
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  cursor: pointer; color: var(--text-subtle); text-align: left; font-size: var(--fs-base);
}
.sb-loc-toggle svg:last-child { color: var(--text-subtle); flex: none; transition: transform var(--t-fast) var(--ease); }
.sb-loc-toggle[aria-expanded="true"] svg:last-child { transform: rotate(180deg); }
/* left/top/width are set from JS on open (position:fixed — see homeMount's
   comment on why: .hero's overflow:hidden clips a plain position:absolute
   popup here otherwise), this just bounds its height. */
.sb-loc-menu { max-height: 18rem; overflow-y: auto; }

.popular-row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-top: 1rem; font-size: var(--fs-sm); }
.popular-row a { padding: .3rem .7rem; border-radius: var(--r-full); background: var(--surface);
  border: 1px solid var(--border); color: var(--text-muted); font-weight: 600; font-size: var(--fs-xs); }
@media (hover: hover) { .popular-row a:hover { border-color: var(--primary); color: var(--primary); text-decoration: none; } }

/* Hero visual card stack */
.hero-visual { position: relative; }
.float-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: 1rem 1.1rem; box-shadow: var(--shadow-lg);
}
.float-card + .float-card { margin-top: 1rem; }
.float-card.offset-a { transform: translateX(-1.5rem); }
.float-card.offset-b { transform: translateX(1.75rem); }
@media (prefers-reduced-motion: no-preference) {
  .float-card { animation: rise .7s var(--ease-out) backwards; }
  .float-card:nth-child(2) { animation-delay: .1s; }
  .float-card:nth-child(3) { animation-delay: .2s; }
}
@keyframes rise { from { opacity: 0; transform: translateY(16px); } }

/* ---------- Stat strip --------------------------------------------------- */
.stat-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.stat { text-align: center; padding: 1.25rem 1rem; }
.stat b { display: block; font-size: clamp(1.5rem, 3vw, 2.1rem); font-weight: 800; letter-spacing: -.03em; color: var(--text); }
.stat span { font-size: var(--fs-sm); color: var(--text-muted); font-weight: 600; }

/* ---------- Internship card ---------------------------------------------- */
.ilist { display: grid; gap: 1rem; }
.icard { position: relative; display: flex; flex-direction: column; gap: .9rem; }
.icard-top { display: flex; gap: .9rem; align-items: flex-start; }
.icard-title { font-size: var(--fs-lg); font-weight: 800; letter-spacing: -.02em; color: var(--text); }
@media (hover: hover) { a.icard-title:hover { color: var(--primary); text-decoration: none; } }
.icard-company { display: flex; align-items: center; gap: .4rem; color: var(--text-muted); font-size: var(--fs-sm); font-weight: 600; margin-top: .15rem; }
.icard-save { margin-left: auto; flex: none; }
.icard-save.saved { color: var(--primary); }

.meta-row { display: flex; flex-wrap: wrap; gap: .35rem 1.1rem; }
.meta { display: flex; align-items: center; gap: .4rem; font-size: var(--fs-sm); color: var(--text-muted); font-weight: 600; }
.meta svg { color: var(--text-subtle); flex: none; }
.meta strong { color: var(--text); font-weight: 700; }

.icard-foot { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; padding-top: .9rem; border-top: 1px solid var(--border); }
.icard-foot .posted { font-size: var(--fs-xs); color: var(--text-subtle); font-weight: 600; }

.match-ring { display: flex; align-items: center; gap: .5rem; }
.ring { --pct: 0; width: 2.5rem; height: 2.5rem; border-radius: 50%; display: grid; place-items: center; flex: none;
  background: conic-gradient(var(--primary) calc(var(--pct) * 1%), var(--bg-sunken) 0); }
.ring i { width: 1.85rem; height: 1.85rem; border-radius: 50%; background: var(--surface);
  display: grid; place-items: center; font-style: normal; font-size: .68rem; font-weight: 800; color: var(--primary); }

/* ---------- Listings page ------------------------------------------------ */
/* Grid items default to min-width:auto, so a child with nowrap content (the
   filter tabs, a long card row) can blow out the track past 1fr. min-width:0
   on every grid content column below prevents that horizontal overflow. */
.listing-layout { display: grid; grid-template-columns: 288px 1fr; gap: 2rem; align-items: start; }
/* `> *`, not `> div`: the dashboard's tab strip is a <nav>, so the old
   selector never reached it. Without min-width:0 a grid item cannot shrink
   below its own min-content, so the strip's full 521px width became the
   column width and the overflow-x:auto below never got a chance to scroll -
   it pushed the whole page sideways instead. */
.listing-layout > *, .dash-layout > *, .detail-layout > * { min-width: 0; }
.filters {
  position: sticky; top: calc(var(--nav-h) + 1rem);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 1.25rem; max-height: calc(100vh - var(--nav-h) - 2rem); overflow-y: auto;
}
.filter-group + .filter-group { margin-top: 1.35rem; padding-top: 1.35rem; border-top: 1px solid var(--border); }
.filter-group > h4 { font-size: var(--fs-sm); font-weight: 800; margin-bottom: .7rem; display: flex; align-items: center; justify-content: space-between; }
.filter-scroll { max-height: 12rem; overflow-y: auto; padding-right: .25rem; }
.filter-bar { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.applied-chips { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: 1rem; }
.filters-toggle { display: none; }

.pagination { display: flex; gap: .35rem; justify-content: center; align-items: center; margin-top: 2rem; flex-wrap: wrap; }
.page-btn {
  min-width: 2.4rem; height: 2.4rem; padding: 0 .6rem; display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface);
  font-weight: 700; font-size: var(--fs-sm); cursor: pointer; color: var(--text-muted);
}
@media (hover: hover) { .page-btn:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); } }
.page-btn[aria-current="page"] { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.page-btn:disabled { opacity: .4; cursor: not-allowed; }

/* ---------- Detail page -------------------------------------------------- */
.detail-layout { display: grid; grid-template-columns: 1fr 340px; gap: 2rem; align-items: start; }
.detail-aside { position: sticky; top: calc(var(--nav-h) + 1rem); display: grid; gap: 1rem; }
.detail-hero { border-bottom: 1px solid var(--border); padding-bottom: 1.5rem; margin-bottom: 1.5rem; }
.prose { line-height: 1.75; }
.prose h3 { margin-top: 1.75rem; margin-bottom: .6rem; font-size: var(--fs-lg); }
.prose h3:first-child { margin-top: 0; }
.prose p { color: var(--text-muted); }
.prose ul { display: grid; gap: .45rem; color: var(--text-muted); margin-top: .5rem; }
.prose li::marker { color: var(--primary); }

.kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr)); gap: 1rem; }
.kv { padding: .9rem 1rem; background: var(--bg-subtle); border-radius: var(--r-md); border: 1px solid var(--border); }
.kv dt { font-size: var(--fs-xs); color: var(--text-subtle); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; }
.kv dd { margin: .25rem 0 0; font-weight: 700; font-size: var(--fs-base); overflow-wrap: anywhere; }

.breadcrumb { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; font-size: var(--fs-sm); color: var(--text-subtle); margin-bottom: 1rem; }
.breadcrumb a { color: var(--text-muted); font-weight: 600; }
.breadcrumb span { opacity: .5; }

/* ---------- Dashboard ---------------------------------------------------- */
.dash-layout { display: grid; grid-template-columns: 250px 1fr; gap: 2rem; align-items: start; }
/* The tabs and Sign out stick together as one block, so Sign out always stays
   directly under the last tab instead of scrolling up over it. */
.dash-side { position: sticky; top: calc(var(--nav-h) + 1rem); }
.dash-nav { display: grid; gap: .2rem; }
.dash-nav a {
  display: flex; align-items: center; gap: .7rem; padding: .65rem .85rem;
  border-radius: var(--r-md); color: var(--text-muted); font-weight: 600;
}
@media (hover: hover) { .dash-nav a:hover { background: var(--surface-hover); color: var(--text); text-decoration: none; } }
.dash-nav a[aria-current="page"] { background: var(--primary-soft); color: var(--primary); }
.dash-nav a .count { margin-left: auto; font-size: var(--fs-xs); font-weight: 800; }

/* Sign out — deliberately a sibling of .dash-nav, not one more row inside
   it. Inside the nav it would scroll away with the tabs on the mobile
   horizontal-tab layout (see that media query below); as a sibling it
   always stays the last, fixed thing under the sidebar on every width. */
.dash-signout {
  display: flex; align-items: center; gap: .7rem; width: 100%; margin-top: .75rem;
  padding: .65rem .85rem; border-radius: var(--r-md); border: 0; background: none;
  color: var(--red-500); font-weight: 600; font-size: var(--fs-base); text-align: left; cursor: pointer;
}
@media (hover: hover) { .dash-signout:hover { background: var(--red-50); } }

.stat-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); gap: 1rem; }
.stat-card { display: flex; align-items: center; gap: .9rem; }
.stat-card .ico { width: 2.6rem; height: 2.6rem; border-radius: var(--r-md); display: grid; place-items: center; flex: none; }
.stat-card b { display: block; font-size: var(--fs-2xl); line-height: 1.1; letter-spacing: -.03em; }
.stat-card span { font-size: var(--fs-sm); color: var(--text-muted); font-weight: 600; }

.tabs {
  display: flex; gap: .25rem; border-bottom: 1px solid var(--border); margin-bottom: 1.5rem; overflow-x: auto;
}
.tab {
  padding: .7rem 1rem; border: 0; background: none; cursor: pointer; font-weight: 700;
  color: var(--text-muted); border-bottom: 2px solid transparent; white-space: nowrap;
}
@media (hover: hover) { .tab:hover { color: var(--text); } }
.tab[aria-selected="true"] { color: var(--primary); border-bottom-color: var(--primary); }

/* Application timeline */
.timeline { display: grid; gap: 0; padding-left: .35rem; }
.tl-step { display: grid; grid-template-columns: auto 1fr; gap: .9rem; }
.tl-rail { display: flex; flex-direction: column; align-items: center; }
.tl-dot { width: .85rem; height: .85rem; border-radius: 50%; border: 2px solid var(--border); background: var(--surface); flex: none; margin-top: .3rem; }
.tl-step.done .tl-dot { background: var(--primary); border-color: var(--primary); }
.tl-step.current .tl-dot { border-color: var(--primary); box-shadow: 0 0 0 4px var(--primary-soft); }
.tl-step.rejected .tl-dot { background: var(--red-500); border-color: var(--red-500); }
.tl-line { width: 2px; flex: 1; background: var(--border); min-height: 1.5rem; }
.tl-step.done .tl-line { background: var(--primary); }
.tl-body { padding-bottom: 1.1rem; }
.tl-body b { font-size: var(--fs-base); }
.tl-body p { font-size: var(--fs-sm); color: var(--text-muted); }

/* Resume score */
.score-ring { --pct: 0; width: 6.5rem; height: 6.5rem; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: conic-gradient(var(--score-color, var(--primary)) calc(var(--pct) * 1%), var(--bg-sunken) 0); }
.score-ring i { width: 5.3rem; height: 5.3rem; border-radius: 50%; background: var(--surface);
  display: grid; place-items: center; font-style: normal; font-size: var(--fs-2xl); font-weight: 800; }
.score-list { display: grid; gap: .6rem; }
.score-row { display: flex; align-items: flex-start; gap: .6rem; font-size: var(--fs-sm); }
.score-row .mark { flex: none; margin-top: .12rem; }
.score-row.pass .mark { color: var(--green-500); }
.score-row.fail .mark { color: var(--amber-500); }

/* ---------- Company / category cards ------------------------------------- */
.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr)); gap: 1.1rem; }
.cat-tile { display: flex; flex-direction: column; gap: .6rem; padding: 1.5rem 1.35rem; }
.cat-tile .ico { width: 2.15rem; height: 2.15rem; border-radius: var(--r-md); display: grid; place-items: center; flex: none;
  background: var(--primary-soft); color: var(--primary); }
.cat-tile-head { display: flex; align-items: center; gap: .65rem; }
.cat-tile b { font-size: var(--fs-md); }
.cat-tile-blurb { flex: 1; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.cat-tile-cta {
  display: inline-flex; align-items: center; gap: .35rem; font-size: var(--fs-sm); font-weight: 700;
  color: var(--primary); opacity: 0; transform: translateX(-4px);
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
}
@media (hover: hover) {
  .cat-tile:hover { text-decoration: none; }
  .cat-tile:hover .cat-tile-cta { opacity: 1; transform: translateX(0); }
}
@media (hover: none) { .cat-tile-cta { opacity: 1; } }

/* ---------- Admin: category manage grid ---------------------------------- */
.admin-cat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr)); gap: 1rem; }
.admin-cat-card {
  position: relative; display: flex; flex-direction: column; gap: .7rem;
  padding: 1.1rem 1.1rem 1rem; border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--surface); transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
@media (hover: hover) { .admin-cat-card:hover { border-color: var(--primary-soft-br); box-shadow: var(--shadow-sm); } }
.admin-cat-card.is-hidden { opacity: .58; }
@media (hover: hover) { .admin-cat-card.is-hidden:hover { opacity: 1; } }
.admin-cat-card .ac-title { min-width: 0; display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; padding-right: 4.5rem; }
.admin-cat-card .ac-ico { width: 1.8rem; height: 1.8rem; border-radius: var(--r-sm); display: grid; place-items: center; flex: none;
  background: var(--primary-soft); color: var(--primary); }
.admin-cat-card .ac-title b { font-size: var(--fs-md); line-height: 1.3; }
.admin-cat-card .ac-count { font-size: var(--fs-xs); color: var(--text-subtle); font-weight: 700; flex-basis: 100%; }
.admin-cat-card .ac-blurb { font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.5; }
.admin-cat-card .ac-actions { display: flex; align-items: center; gap: .4rem; margin-top: auto; padding-top: .7rem; border-top: 1px dashed var(--border); }
.admin-cat-card .ac-status { position: absolute; top: .8rem; right: .8rem; }

/* ---------- Admin: category icon picker ----------------------------------- */
.icon-pick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(2.6rem, 1fr)); gap: .5rem; }
.icon-pick {
  width: 2.6rem; height: 2.6rem; border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-muted); display: grid; place-items: center; cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
@media (hover: hover) { .icon-pick:hover { border-color: var(--primary-soft-br); color: var(--primary); } }
.icon-pick.is-selected { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }
.icon-manual-row { display: flex; align-items: center; gap: .6rem; }
.icon-manual-preview { flex: none; color: var(--primary); cursor: default; }
.icon-manual-row .input { flex: 1; }

.skill-cloud { display: flex; flex-wrap: wrap; gap: .65rem; }
/* Green by default, not only on hover. These are the one thing on the
   homepage a student is meant to click straight away, and a row of grey
   pills read as disabled labels rather than links. Uses the same
   primary-soft / primary pair as every other interactive chip on the site,
   so it stays one visual language. A soft shadow even at rest (not just on
   hover) is what makes a flat tinted pill read as a pressable chip rather
   than a plain label — the same cue --shadow-sm gives every card. */
.skill-pill {
  padding: .55rem 1.1rem; border-radius: var(--r-full);
  border: 1px solid var(--primary-soft-br); background: var(--primary-soft);
  font-weight: 600; font-size: var(--fs-sm); color: var(--primary);
  box-shadow: var(--shadow-sm);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
@media (hover: hover) {
  .skill-pill:hover {
    border-color: var(--primary); background: var(--primary); color: var(--on-primary);
    text-decoration: none; transform: translateY(-2px); box-shadow: var(--shadow-md);
  }
}
.skill-pill:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .skill-pill { transition: none; } .skill-pill:hover { transform: none; } }

/* ---------- Steps / how it works ----------------------------------------- */
/* A fixed four-track grid, not auto-fit. auto-fit resolved to three columns
   at common desktop widths and dropped step 4 onto a row of its own, which
   read as a layout bug rather than a sequence — and a "four steps" heading
   above a 3+1 split is the first thing that makes a page look unfinished.
   Four steps, four columns, then an honest 2x2 and a single column further
   down. */
.steps {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem;
  counter-reset: step; list-style: none; padding: 0; margin: 0;
}
.step {
  counter-increment: step; position: relative;
  padding: 1.5rem 1.3rem 1.35rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
@media (hover: hover) { .step:hover { border-color: var(--primary-soft-br); box-shadow: var(--shadow-sm); transform: translateY(-2px); } }

/* The number stays a CSS counter so the sequence can never disagree with the
   order the cards are actually in. */
.step::before {
  content: counter(step); display: grid; place-items: center;
  width: 2.1rem; height: 2.1rem; border-radius: var(--r-full);
  background: var(--primary); color: var(--on-primary);
  font-weight: 800; font-size: var(--fs-sm); margin-bottom: .9rem;
}

/* The line joining one step to the next. Drawn across the grid gap rather
   than inside a card, so it reads as a flow instead of four unrelated
   boxes. Dropped the moment the grid stops being a single row, because a
   connector pointing off the end of a wrapped row points at nothing. */
.step::after {
  content: ""; position: absolute; top: 2.55rem; left: calc(100% + 1px);
  width: 1.25rem; height: 1px; background: var(--border);
}
.step:last-child::after { display: none; }

.step h4 { margin-bottom: .35rem; font-size: var(--fs-md); }
.step p { color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.6; }

@media (max-width: 980px) {
  .steps { grid-template-columns: repeat(2, 1fr); }
  /* Only the first of each row still has a neighbour beside it. */
  .step:nth-child(even)::after { display: none; }
}
@media (max-width: 560px) {
  .steps { grid-template-columns: 1fr; }
  .step::after { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .step { transition: none; }
  @media (hover: hover) { .step:hover { transform: none; } }
}

/* ---------- CTA band ----------------------------------------------------- */
.cta-band {
  background: linear-gradient(135deg, var(--teal-700), var(--teal-900));
  border-radius: var(--r-xl); padding: clamp(2rem, 5vw, 3.5rem); color: #fff; text-align: center;
}
.cta-band h2 { color: #fff; }
.cta-band p { color: rgba(255, 255, 255, .82); max-width: 34rem; margin: .75rem auto 1.75rem; }
.cta-band .btn-primary { --btn-bg: #fff; --btn-fg: var(--teal-800); --btn-br: #fff; }
@media (hover: hover) { .cta-band .btn-primary:hover { --btn-bg: var(--teal-50); --btn-br: var(--teal-50); } }
.cta-band .btn-outline { --btn-fg: #fff; --btn-br: rgba(255, 255, 255, .45); --btn-bg: transparent; }
@media (hover: hover) { .cta-band .btn-outline:hover { --btn-bg: rgba(255, 255, 255, .12); --btn-fg: #fff; --btn-br: #fff; } }

/* ---------- Auth --------------------------------------------------------- */
.auth-wrap { max-width: 26rem; margin: clamp(2rem, 6vw, 4rem) auto; }
.auth-wrap-wide { max-width: 34rem; }
.auth-card { padding: 2rem; }
.role-toggle { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; margin-bottom: 1.25rem; }
.role-opt input { position: absolute; opacity: 0; }
.role-opt span {
  display: flex; align-items: center; justify-content: center; gap: .45rem;
  padding: .7rem; border-radius: var(--r-md);
  border: 1px solid var(--border); font-weight: 700; cursor: pointer; font-size: var(--fs-sm);
}
.role-opt span svg { flex: none; }
.role-opt input:checked + span { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }
.role-opt input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Two equal tracks need ~103px each at a 320px viewport, and "I am an
   employer" plus its icon does not fit in that - the label was clipped on
   the smallest phones. Stacking is better than shrinking here: these are
   the first control a new user touches, and full-width rows are easier to
   hit than two cramped ones. */
@media (max-width: 380px) {
  .role-toggle { grid-template-columns: 1fr; }
}

/* ---------- Responsive --------------------------------------------------- */
@media (max-width: 1080px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-visual { display: none; }
  .detail-layout { grid-template-columns: 1fr; }
  .detail-aside { position: static; }
}
@media (max-width: 900px) {
  .nav-links { display: none; }
  /* Two tracks, not three, once the links are hidden. `display: none`
     takes .nav-links out of the grid altogether, so auto-placement moved
     .nav-actions into the middle `auto` track - parking the avatar and
     the Get started button in the centre of the header on every phone.
     justify-self: end could not fix that: the middle track is only as
     wide as its content, so there was no room to push into. Dropping to
     `1fr auto` puts the brand left and the actions hard right. */
  .nav { grid-template-columns: 1fr auto; }
  .nav-toggle { display: inline-flex; }
  .hide-sm { display: none; }
  .nav-actions { gap: .3rem; }
  .listing-layout { grid-template-columns: 1fr; }
  .filters {
    position: fixed; inset: 0; z-index: 110; max-height: none; border-radius: 0;
    border: 0; overflow-y: auto; padding-bottom: 6rem; display: none;
  }
  .filters.open { display: block; }
  .filters-toggle { display: inline-flex; }
  .dash-layout { grid-template-columns: 1fr; }
  /* Scrolls sideways when the tabs don't fit, but with the bar itself
     hidden — it's a short, obviously-swipeable row of tabs, and a visible
     scrollbar sitting under them read as a stray horizontal scroll on the
     page rather than as part of the control. Still fully scrollable by
     swipe, wheel, and keyboard. */
  /* Tabs and Sign out share ONE line: the tabs scroll sideways inside the space that is left, and
     Sign out stays pinned at the right end instead of dropping onto a second line. */
  .dash-side { position: static; display: flex; align-items: center; gap: .5rem;
    padding-bottom: .5rem; border-bottom: 1px solid var(--border); }
  .dash-nav { flex: 1 1 auto; min-width: 0; grid-auto-flow: column; grid-auto-columns: max-content;
    overflow-x: auto; scrollbar-width: none; }
  .dash-nav::-webkit-scrollbar { display: none; }
  .dash-nav a .count { display: none; }
  .dash-signout { flex: none; width: auto; margin-top: 0; padding: .5rem .7rem; gap: .4rem;
    font-size: var(--fs-sm); white-space: nowrap; border-left: 1px solid var(--border); border-radius: 0 var(--r-md) var(--r-md) 0; }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 2rem; }
  .footer-col-cats { grid-column: 1 / -1; }
  .searchbar { grid-template-columns: 1fr; }
  .searchbar .sb-sep { display: none; }
  .stat-strip { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 420px) {
  .brand-logo { height: 2.2rem; }
  .nav { padding-inline: .75rem; gap: .5rem; }
  .nav-actions { gap: .15rem; }
}
@media (max-width: 560px) {
  :root { --fs-4xl: 2.2rem; --fs-3xl: 1.7rem; }
  .footer-grid { grid-template-columns: 1fr; }
  .toast-root { left: 1rem; right: 1rem; bottom: 1rem; }
  .toast { max-width: none; }
  .icard-foot { flex-direction: column; align-items: stretch; }
  /* .btn is nowrap by design, which is right for a short label and wrong
     for one built from user-supplied text. These are full-width stacked
     buttons here, so wrapping costs nothing and guarantees no future long
     name can push the card wider than its column. */
  .icard-foot .btn { width: 100%; white-space: normal; }
}

/* ---------- Print --------------------------------------------------------
 * The resume builder no longer uses the browser's print dialog (it draws a
 * real PDF itself — see js/resume/pdf.js), but this still applies to
 * anything else on the site someone prints. */
@media print {
  .site-header, .site-footer, .no-print, .toast-root { display: none !important; }
  body { background: #fff; }
}

/* ---------- Student story cards -------------------------------------------
 * The homepage testimonials. Given a little more structure than a plain
 * card: the quote is the point, so it gets the size, and the attribution is
 * pushed to a footer separated by a rule rather than floating under the
 * text. Cards stretch to equal height so a short quote does not leave a
 * ragged row. */
.story-card {
  margin: 0; display: flex; flex-direction: column; gap: .9rem;
  padding: 1.6rem 1.5rem 1.4rem; height: 100%;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
@media (hover: hover) { .story-card:hover { border-color: var(--primary-soft-br); box-shadow: var(--shadow-sm); transform: translateY(-2px); } }

.story-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.story-mark {
  display: grid; place-items: center; width: 2.1rem; height: 2.1rem; flex: none;
  border-radius: var(--r-md); background: var(--primary-soft); color: var(--primary);
}

.story-stars { display: inline-flex; gap: .1rem; }
/* Unfilled stars are grey, not a pale amber: a washed-out version of the
   same colour reads as a rendering glitch, a grey one reads as "not given". */
.story-stars .star { color: var(--text-subtle); display: inline-flex; opacity: .45; }
.story-stars .star.is-on { color: var(--amber-500); opacity: 1; }

.story-body { margin: 0; flex: 1; }
.story-body p { font-size: var(--fs-base); line-height: 1.65; color: var(--text); }

.story-foot {
  display: flex; align-items: center; gap: .7rem;
  padding-top: 1rem; border-top: 1px solid var(--border);
}
.story-foot b { display: block; font-size: var(--fs-sm); line-height: 1.3; }
.story-foot small { font-size: var(--fs-xs); color: var(--text-muted); }

@media (prefers-reduced-motion: reduce) {
  .story-card { transition: none; }
  @media (hover: hover) { .story-card:hover { transform: none; } }
}

/* The View resume button inside an applicant card, aligned to the far side
   of its row so it does not read as part of the cover letter beside it.
   Only while the grid is genuinely two columns - once it wraps, right
   alignment would leave the button stranded away from the text it follows. */
.ap-resume-cell { justify-self: start; }
@media (min-width: 720px) {
  .ap-resume-cell { justify-self: end; }
}

/* ==========================================================================
   Touch devices
   --------------------------------------------------------------------------
   Scoped to `pointer: coarse` (a thumb) rather than to a narrow viewport: a
   half-width window on a laptop still has a mouse and does not need larger
   targets, while a 1024px tablet does.
   ========================================================================== */
@media (pointer: coarse) {
  /* 16px is not cosmetic here. Mobile Safari zooms the page in when a field
     smaller than 16px takes focus, and never zooms back out - so on an
     iPhone, tapping any input left the whole site enlarged and scrolled
     sideways. Set in px deliberately: a rem would re-resolve below the
     threshold if the root size ever changes. */
  .input, .select, .textarea { font-size: 16px; }

  /* Buttons measured 31-35px tall on a phone. 44px is the accessibility
     guideline for a thumb; min-height rather than height so a button with
     wrapped text still grows instead of clipping. */
  .btn { min-height: 44px; }
  .btn-sm { min-height: 40px; padding-block: .5rem; }
  .btn-icon { min-height: 44px; min-width: 44px; }

  /* Same reasoning for the controls that are not .btn but are still tapped. */
  .input, .select, .textarea { min-height: 44px; }
  .textarea { min-height: 7rem; }

  /* Nothing needed here for hover any more: every hover rule in the
     stylesheet now sits behind (hover: hover), so none of them reach a
     touch device and there is no stuck state left to undo. */
}

/* .row is a nowrap flex row by default, which is right on a wide screen and
   wrong on a narrow one: pairs of buttons (the guidance page) and a logo
   beside a long company name were overflowing their card rather than
   moving onto a second line. flex-wrap only engages when the content does
   not fit, so this is inert wherever the row already fits - including the
   .row.between header rows that rely on staying on one line. */
@media (max-width: 560px) {
  .row { flex-wrap: wrap; }

  /* A title block sitting beside a status badge. Letting the block shrink
     (min-width:0) stopped the card overflowing, but flex shrinks before it
     wraps - so the title collapsed into a ~110px ribbon of text with the
     badge holding the rest of the row. Giving the block a flex-basis means
     the badge no longer fits alongside and drops to its own line instead,
     and the title gets the full width of the card. */
  .row.between > .row:first-child { flex: 1 1 12rem; }
  .row.between > .status { flex: none; }
}

/* Two-column grids that collapse to one on a narrow screen.
   These existed only as inline `grid-template-columns` values, which no
   media query can override - an inline style always wins - so they stayed
   two columns on phones and pushed their pages sideways. Kept as classes
   precisely so the breakpoint below can reach them. */
.grid-2 { grid-template-columns: 1fr 1fr; }
.grid-2-wide { grid-template-columns: 2fr 1fr; }
.grid-2-lean { grid-template-columns: 1.4fr 1fr; }
@media (max-width: 760px) {
  .grid-2, .grid-2-wide, .grid-2-lean { grid-template-columns: 1fr; }
}

/* The menu button shares a 320-375px header with the brand and the
   Get started CTA, and at 44px square it crowded both. Trimmed to a 40px
   box with an 18px glyph: visibly lighter, still comfortably tappable.
   Deliberately after the `pointer: coarse` block so it wins there - equal
   specificity, later wins - because that block's 44px minimum is what made
   it wide in the first place. */
@media (max-width: 430px) {
  .nav-toggle {
    width: 40px; height: 40px; min-width: 40px; min-height: 40px; padding: .3rem;
  }
  .nav-toggle svg { width: 18px; height: 18px; }
}

/* Clearance for the floating chat button. It is 3.5rem plus a 1.25rem
   inset, fixed to the bottom-right, and the stylesheet already lifts
   toasts clear of it - but nothing kept it off the end of the page, so on
   a phone it sat on top of whatever the last row of the footer happened to
   be. Floating over mid-page content while scrolling is expected of a
   launcher; permanently covering the bottom of the page is not.
   :has() so the space is only reserved when the launcher is actually
   rendered - it is not there for signed-out visitors. */
@media (max-width: 560px) {
  body:has(.cw-launcher) .site-footer { padding-bottom: 5.5rem; }
}

/* ---------- Mobile navigation (below 768px) ------------------------------
   On a phone the logo is the menu trigger (header.js), so the 3-dot button
   is not shown. Tablets (768-900px) are deliberately untouched: they keep
   the button, and the logo there still goes home. Because the logo no
   longer goes home on a phone, the drawer carries its own Home link, shown
   only at this width so the tablet drawer is exactly as it was. */
.mobile-drawer .drawer-home { display: none; }
@media (max-width: 767px) {
  .nav-toggle { display: none; }
  .mobile-drawer .drawer-home { display: block; }
}
/* The drawer only belongs where the nav links are hidden. It now stays in
   the page when closed, so above that width it has to be taken out. */
@media (min-width: 901px) {
  .mobile-drawer { display: none; }
}

/* The notifications dropdown (.menu.menu-wide) is anchored with right:0
   against the bell's own small wrapper, not the true edge of the screen —
   the bell sits well left of the viewport's right edge once the avatar menu
   is also in the header, so a 22rem-wide panel positioned that way runs off
   the LEFT of a phone screen instead of fitting inside it. Below 768px it
   becomes a full-screen sheet under the header instead (same "own screen
   real estate" pattern the hamburger .mobile-drawer above already uses),
   which sidesteps the anchoring math entirely rather than trying to keep
   patching the offset for every screen width. */
.notif-close { display: none; }
@media (max-width: 767px) {
  .menu.menu-wide {
    position: fixed; inset: var(--nav-h) 0 0; z-index: 95;
    width: auto; min-width: 0; max-height: none; height: calc(100vh - var(--nav-h));
    border: 0; border-top: 1px solid var(--border); border-radius: 0;
    box-shadow: none; padding: 0;
  }
  .menu.menu-wide .menu-head { padding: .85rem 1rem; border-bottom: 1px solid var(--border); }
  .menu.menu-wide .notif-item { padding: .85rem 1rem; border-radius: 0; }
  .notif-close { display: grid; }
}

/* ---------- Companies directory (pages/companies.js) ----------------------- */
.co-hero { background: linear-gradient(135deg, var(--primary-soft) 0%, var(--bg-subtle) 62%, var(--surface) 100%); border-bottom: 1px solid var(--border); }
.co-hero-inner { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 2rem; align-items: center; padding-block: clamp(1.75rem, 4vw, 2.75rem); }
.co-hero-main { display: flex; gap: 1.1rem; align-items: center; }
.co-hero-icon { width: 4.75rem; height: 4.75rem; flex: none; display: grid; place-items: center; border-radius: var(--r-xl); background: var(--surface); color: var(--primary); border: 1px solid var(--primary-soft-br); box-shadow: var(--shadow-sm); }
.co-hero h1 { font-size: clamp(1.6rem, 3.4vw, 2.35rem); letter-spacing: -.03em; margin: .15rem 0 .4rem; }
.co-hero p { color: var(--text-muted); max-width: 34rem; }
.co-hero-features { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
.co-feature { display: flex; align-items: center; gap: .65rem; min-width: 0; }
.co-feature-ico, .co-stat-ico { width: 2.6rem; height: 2.6rem; flex: none; display: grid; place-items: center; border-radius: 50%; background: var(--surface); color: var(--primary); border: 1px solid var(--primary-soft-br); }
.co-feature b { display: block; font-size: var(--fs-sm); }
.co-feature small, .co-stat small { display: block; color: var(--text-muted); font-size: var(--fs-xs); line-height: 1.35; }

.co-filters { display: grid; grid-template-columns: minmax(0, 2.2fr) repeat(3, minmax(0, 1fr)) auto; gap: .6rem; align-items: center;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: .7rem; box-shadow: var(--shadow-sm); }
.co-search { display: flex; align-items: center; gap: .55rem; min-width: 0; height: 2.75rem; padding: 0 .85rem; color: var(--text-subtle);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); }
.co-search:focus-within { border-color: var(--primary); }
.co-search input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; color: var(--text); font: inherit; }
.co-filters .themed-select { width: 100%; }
.co-filters .select-toggle { width: 100%; height: 2.75rem; }
.co-filters .btn { height: 2.75rem; white-space: nowrap; }

.co-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); margin-top: 1rem; background: var(--primary-soft);
  border: 1px solid var(--primary-soft-br); border-radius: var(--r-lg); overflow: hidden; }
.co-stat { display: flex; align-items: center; gap: .8rem; padding: .9rem 1.25rem; }
.co-stat + .co-stat { border-left: 1px solid var(--primary-soft-br); }
.co-stat b { display: block; font-size: 1.15rem; line-height: 1.2; }

.co-explore-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; margin: 1.75rem 0 1rem; }
.co-explore-head h2 { font-size: var(--fs-xl); }
.co-sort { display: flex; align-items: center; gap: .6rem; color: var(--text-muted); font-size: var(--fs-sm); }
.co-sort .themed-select { min-width: 11.5rem; }

.co-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(19rem, 100%), 1fr)); gap: 1.1rem; }
.co-card { display: flex; flex-direction: column; gap: .85rem; padding: 1.15rem; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm); transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease; }
@media (hover: hover) { .co-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--primary-soft-br); } }
.co-card-top { display: flex; align-items: center; gap: .75rem; }
.co-logo { width: 3rem; height: 3rem; flex: none; border-radius: var(--r-md); object-fit: cover; border: 1px solid var(--border); background: var(--surface); }
.co-card-id { min-width: 0; flex: 1; }
.co-card-name { display: -webkit-box; font-weight: 800; color: var(--text); line-height: 1.3; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.co-card-name:hover { color: var(--primary); text-decoration: none; }
.co-card-id span { display: block; color: var(--text-muted); font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.co-verified { flex: none; align-self: flex-start; display: inline-flex; align-items: center; gap: .25rem; padding: .2rem .55rem; border-radius: var(--r-full);
  background: var(--green-50); color: var(--green-600); font-size: var(--fs-xs); font-weight: 700; }
:root[data-theme="dark"] .co-verified { color: #4ADE80; }
.co-card-meta { display: grid; gap: .45rem; font-size: var(--fs-sm); color: var(--text-muted); }
.co-card-meta > span { display: flex; align-items: center; gap: .45rem; min-width: 0; }
.co-card-meta svg { flex: none; color: var(--primary); }
.co-open { color: var(--primary); font-weight: 700; }
.co-closed { color: var(--text-subtle); }
.co-card-about { flex: 1; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.55; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.co-card-cta { margin-top: auto; }

@media (max-width: 1000px) {
  .co-hero-inner { grid-template-columns: 1fr; gap: 1.25rem; }
  .co-filters { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .co-search, .co-filters .btn { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .co-hero-features { grid-template-columns: 1fr; gap: .7rem; }
  .co-hero-icon { width: 3.6rem; height: 3.6rem; border-radius: var(--r-lg); }
  .co-filters { grid-template-columns: 1fr; }
  .co-stat { padding: .75rem 1rem; }
  .co-stat + .co-stat { border-left: 0; border-top: 1px solid var(--primary-soft-br); }
  .co-explore-head { align-items: flex-start; }
}
.co-loading { opacity: .45; pointer-events: none; transition: opacity .15s ease; }
.duration-custom { margin-top: .6rem; }
.duration-custom .input { max-width: 12rem; }
