/* ==========================================================================
   Yonoio — Global stylesheet
   --------------------------------------------------------------------------
   Sections in this file, in cascade order:

     1.  Design tokens
     2.  Reset & base elements
     3.  Layout: containers, sections, grid
     4.  Accessibility helpers
     5.  Typography helpers
     6.  Buttons
     7.  Cards
     7d. App detail page
     8.  Badges
     9.  Media & images
     10. Announcement bar, site header & primary navigation
     11. Hero
     12. Section headings
     13. Placeholder blocks (temporary scaffolding)
     14. Site footer
     15. Reduced motion & print

   Phase 2 scope: sections 1-9 are the reusable global design system. The
   complete header, hero, featured cards and app directory are NOT built
   here — later phases compose them out of the primitives above.
   ========================================================================== */


/* ==========================================================================
   1. DESIGN TOKENS

   Every colour, space, radius, shadow and type size in this file comes from
   here. Change a value once and it updates sitewide.

   Colour budget, kept deliberately tight so the page stays calm while the
   app artwork itself is loud:
     - ~85% neutral dark surfaces
     - one PRIMARY accent (green) for actions and interactive state
     - one SECONDARY accent (violet) for classification and highlights
     - gold, reserved exclusively for star ratings
     - three medal tints, reserved exclusively for podium ranks
   ========================================================================== */

:root {

  /* --- 1.1 Surfaces -------------------------------------------------------
     Four lightness steps. Adjacent sections are separated by stepping
     between these rather than by drawing borders or dropping shadows. */
  --bg-page:          #0b0f14;
  --bg-band:          #10151c;
  --bg-surface:       #171e26;
  --bg-raised:        #202a35;

  /* --- 1.2 Cards ----------------------------------------------------------
     Cards are the most-repeated surface on the site, so they get their own
     tokens instead of reaching for the raw surface steps. */
  --card-bg:          #171e26;
  --card-bg-hover:    #1d2732;
  --card-border:      rgba(255, 255, 255, 0.07);
  --card-border-hover: rgba(31, 209, 139, 0.32);

  /* --- 1.3 Lines & edges -------------------------------------------------- */
  --line:             rgba(255, 255, 255, 0.07);
  --line-strong:      rgba(255, 255, 255, 0.14);
  --line-accent:      rgba(31, 209, 139, 0.35);
  --edge-light:       inset 0 1px 0 rgba(255, 255, 255, 0.05);

  /* --- 1.4 Text -----------------------------------------------------------
     The muted values are chosen to stay above 4.5:1 contrast against
     --bg-surface, so card metadata remains readable. */
  --text:             #f1f5f8;
  --text-muted:       #a7b3bf;
  --text-dim:         #7c8895;

  /* --- 1.5 Accents --------------------------------------------------------
     *-ink is the dark text colour to use ON TOP of that accent as a fill.
     Dark-on-bright is what keeps CTAs legible; white on mid-green would
     fail contrast. */

  /* Primary — actions, links, focus, interactive state. */
  --brand:            #1fd18b;
  --brand-hover:      #2ae09a;
  --brand-soft:       rgba(31, 209, 139, 0.12);
  --brand-ink:        #06170f;

  /* Secondary — categories, tags, "new"/"mod" markers, accent highlights.
     Violet reads premium against the green without competing for the
     "this is a button" meaning. */
  --accent:           #7b61ff;
  --accent-hover:     #8f79ff;
  --accent-soft:      rgba(123, 97, 255, 0.14);
  --accent-ink:       #0c0821;

  /* Ratings only. */
  --star:             #ffc23c;

  /* Podium ranks only. */
  --rank-1:           #ffd166;
  --rank-2:           #c9d2db;
  --rank-3:           #e0965c;

  /* Status. */
  --danger:           #ff6b6b;

  /* --- 1.6 Gradients, scrims & glass --------------------------------------
     Used sparingly: gradients belong on small accents and section glows,
     never as a full-page background. */
  --grad-brand:       linear-gradient(135deg, #2ae09a 0%, #13b5a6 100%);
  --grad-accent:      linear-gradient(135deg, #7b61ff 0%, #b65cff 100%);
  --grad-hairline:    linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.14), transparent);

  /* Announcement bar: deep teal -> navy -> deep violet. Saturated enough to
     feel premium, dark enough to stay out of the content's way. */
  --grad-topbar:      linear-gradient(90deg, #0e3229 0%, #14223d 52%, #241a42 100%);

  /* Accent rule under the sticky header, faded at both ends. */
  --grad-underline:   linear-gradient(90deg, transparent 0%, rgba(31, 209, 139, 0.45) 50%, transparent 100%);

  /* Darkens photographic backgrounds so text stays readable over them. */
  --scrim:            linear-gradient(180deg, rgba(8, 11, 15, 0.55) 0%, rgba(8, 11, 15, 0.88) 100%);

  /* Hero layers. The scrim is the readability guarantee: whatever artwork is
     dropped into the hero, these values keep body text above 4.5:1. The
     mobile variant is heavier because the portrait crop shows more of the
     bright upper half of the image behind the text.
     The glow sits ON TOP of the scrim, adding brand light back into a
     flattened image so the hero reads cinematic rather than grey. */
  --hero-scrim:        linear-gradient(180deg,
                         rgba(7, 10, 14, 0.60) 0%,
                         rgba(7, 10, 14, 0.72) 42%,
                         rgba(11, 15, 20, 0.88) 100%);
  --hero-scrim-strong: linear-gradient(180deg,
                         rgba(7, 10, 14, 0.72) 0%,
                         rgba(7, 10, 14, 0.82) 40%,
                         rgba(11, 15, 20, 0.90) 100%);
  --hero-glow:         radial-gradient(64% 52% at 16% 12%, rgba(31, 209, 139, 0.18) 0%, transparent 62%),
                       radial-gradient(58% 48% at 86% 18%, rgba(123, 97, 255, 0.18) 0%, transparent 62%);

  /* Light search pill sitting on the dark hero. */
  --hero-search-bg:         #f4f7f9;
  --hero-search-bg-frost:   rgba(244, 247, 249, 0.94);
  --hero-search-placeholder:#6b7785;

  /* Cinematic glow for major promotional sections. */
  --spotlight:        radial-gradient(60% 60% at 50% 0%, rgba(31, 209, 139, 0.10) 0%, transparent 70%);

  --glass-bg:         rgba(14, 19, 26, 0.62);
  --glass-blur:       14px;

  /* --- 1.7 Spacing scale (4px base) -------------------------------------- */
  --sp-1:             0.25rem;
  --sp-2:             0.5rem;
  --sp-3:             0.75rem;
  --sp-4:             1rem;
  --sp-5:             1.25rem;
  --sp-6:             1.5rem;
  --sp-8:             2rem;
  --sp-10:            2.5rem;
  --sp-12:            3rem;
  --sp-16:            4rem;

  /* Fluid rhythm values. */
  --section-y:        clamp(2.5rem, 6vw, 4.5rem);
  --gutter:           clamp(1rem, 4vw, 1.5rem);
  --grid-gap:         clamp(0.625rem, 1.4vw, 1rem);

  /* --- 1.8 Container widths ---------------------------------------------- */
  --container-wide:   1440px;   /* full-bleed-ish promotional rows */
  --container:        1280px;   /* default page width */
  --container-narrow: 960px;    /* focused single-column content */
  --container-prose:  72ch;     /* long-form reading measure */

  --header-h:         64px;

  /* --- 1.9 Radius ---------------------------------------------------------
     --r-icon is a percentage so app icons keep the same squircle
     proportion at every rendered size. */
  --r-sm:             8px;
  --r-md:             14px;
  --r-lg:             20px;
  --r-xl:             28px;
  --r-icon:           22%;
  --r-pill:           999px;

  /* --- 1.10 Shadows -------------------------------------------------------
     Conventional drop shadows are nearly invisible on a near-black page, so
     depth comes from --line + a surface step + --edge-light. The two glow
     tokens are reserved for featured/ranked content so that "glow" reliably
     means "important". */
  --sh-1:             0 1px 2px rgba(0, 0, 0, 0.4);
  --sh-2:             0 8px 24px rgba(0, 0, 0, 0.45);
  --sh-3:             0 18px 44px rgba(0, 0, 0, 0.55);
  --glow-brand:       0 0 0 1px rgba(31, 209, 139, 0.28), 0 14px 36px rgba(31, 209, 139, 0.12);
  --glow-accent:      0 0 0 1px rgba(123, 97, 255, 0.30), 0 14px 36px rgba(123, 97, 255, 0.14);

  /* --- 1.11 Typography ----------------------------------------------------
     System font stack: no third-party request, no font-swap layout shift. */
  --font-sans:        system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono:        ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;

  --fs-h1:            clamp(1.75rem, 4.2vw, 2.75rem);
  --fs-hero:          clamp(1.5rem, 4vw, 2.35rem);   /* hero H1 only */
  --fs-h2:            clamp(1.125rem, 2.2vw, 1.5rem);
  --fs-h3:            clamp(1rem, 1.6vw, 1.125rem);
  --fs-h4:            1rem;
  --fs-body:          1rem;
  --fs-sm:            0.875rem;
  --fs-xs:            0.8125rem;   /* readability floor — do not go below */

  --lh-tight:         1.15;
  --lh-snug:          1.35;
  --lh-body:          1.6;
  --track-tight:      -0.02em;
  --track-wide:       0.06em;

  /* --- 1.12 Motion ------------------------------------------------------- */
  --ease:             cubic-bezier(0.4, 0, 0.2, 1);
  --dur:              0.18s;
  --dur-slow:         0.32s;

  /* --- 1.13 Stacking order ----------------------------------------------- */
  --z-base:           1;
  --z-raised:         10;
  --z-nav-panel:      90;
  --z-header:         100;
  --z-skip:           200;
}


/* ==========================================================================
   2. RESET & BASE ELEMENTS
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--sp-4));
}

body {
  margin: 0;
  background-color: var(--bg-page);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --- Headings ------------------------------------------------------------ */

h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0 0 var(--sp-3);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-tight);
  font-weight: 700;
  text-wrap: balance;
}

h1 { font-size: var(--fs-h1); font-weight: 800; }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); line-height: var(--lh-snug); }
h4 { font-size: var(--fs-h4); }
h5,
h6 { font-size: var(--fs-sm); }

/* --- Text --------------------------------------------------------------- */

p {
  margin: 0 0 var(--sp-4);
  text-wrap: pretty;
}

p:last-child {
  margin-bottom: 0;
}

small {
  font-size: var(--fs-xs);
}

strong,
b {
  font-weight: 700;
  color: var(--text);
}

code,
kbd,
samp {
  padding: 0.1em 0.35em;
  border-radius: var(--r-sm);
  background-color: var(--bg-raised);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.9em;
}

/* --- Links --------------------------------------------------------------- */

a {
  color: var(--brand);
  text-decoration: none;
  transition: color var(--dur) var(--ease);
}

a:hover {
  color: var(--brand-hover);
  text-decoration: underline;
}

/* Underline inline links inside body copy for clarity, but leave links that
   are themselves components (cards, nav, buttons) alone. */
main p > a:not([class]) {
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* --- Lists -------------------------------------------------------------- */

ul,
ol {
  margin: 0 0 var(--sp-4);
  padding-left: var(--sp-6);
}

li + li {
  margin-top: var(--sp-1);
}

/* --- Media -------------------------------------------------------------- */

img,
picture,
svg,
video,
canvas {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Placeholder tint while an image decodes, so cards do not flash white. */
img {
  background-color: var(--bg-raised);
}

svg {
  fill: currentColor;
}

/* --- Forms -------------------------------------------------------------- */

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
}

input,
select,
textarea {
  background-color: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--text);
}

input::placeholder,
textarea::placeholder {
  color: var(--text-dim);
  opacity: 1;
}

/* --- Misc --------------------------------------------------------------- */

hr {
  height: 1px;
  margin: var(--sp-8) 0;
  border: 0;
  background-image: var(--grad-hairline);
}

::selection {
  background-color: var(--brand);
  color: var(--brand-ink);
}

/* One consistent focus ring for every interactive element. */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}


/* ==========================================================================
   3. LAYOUT: CONTAINERS, SECTIONS, GRID
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--wide   { max-width: var(--container-wide); }
.container--narrow { max-width: var(--container-narrow); }
.container--prose  { max-width: var(--container-prose); }

/* --- Sections ----------------------------------------------------------- */

.section {
  padding-block: var(--section-y);
}

/* Alternating band: separates adjacent sections by a lightness step. */
.section--band {
  background-color: var(--bg-band);
  border-block: 1px solid var(--line);
}

/* Cinematic treatment for major promotional areas. The glow sits in a
   pseudo-element so it never tints the section's own content. */
.section--spotlight {
  position: relative;
  isolation: isolate;
  background-color: var(--bg-band);
  border-block: 1px solid var(--line);
}

.section--spotlight::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--spotlight);
  pointer-events: none;
}

/* --- Auto grid ----------------------------------------------------------
   The one grid primitive the site needs. Set --min per use to control how
   many columns fit; the track count then reflows continuously instead of
   needing a media query at every breakpoint.

     <ul class="auto-grid" style="--min: 150px">

   Later phases use this for the app tile grid and the category list. */
.auto-grid {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(auto-fill, minmax(min(var(--min, 220px), 100%), 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

.auto-grid > li + li {
  margin-top: 0;   /* cancel the base list rhythm; the grid gap handles it */
}


/* ==========================================================================
   4. ACCESSIBILITY HELPERS
   ========================================================================== */

/* Available to screen readers, hidden visually. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: var(--sp-2);
  left: var(--sp-2);
  z-index: var(--z-skip);
  padding: var(--sp-2) var(--sp-4);
  transform: translateY(-200%);
  border-radius: var(--r-sm);
  background-color: var(--brand);
  color: var(--brand-ink);
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--dur) var(--ease);
}

.skip-link:focus {
  transform: translateY(0);
}


/* ==========================================================================
   5. TYPOGRAPHY HELPERS
   Deliberately only three. Everything else uses real element styles.
   ========================================================================== */

/* Supporting paragraph under a heading. */
.lead {
  max-width: 62ch;
  color: var(--text-muted);
  font-size: clamp(0.9375rem, 1.6vw, 1.0625rem);
}

.text-muted { color: var(--text-muted); }
.text-dim   { color: var(--text-dim); }


/* ==========================================================================
   6. BUTTONS

   Bright accent fill with DARK text. Minimum 44px tall so every button is a
   comfortable tap target on touch devices.
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-2) var(--sp-6);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: var(--fs-sm);
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}

.btn:hover {
  text-decoration: none;
}

.btn[aria-disabled="true"],
.btn:disabled {
  opacity: 0.5;
  pointer-events: none;
}

/* --- Variants ----------------------------------------------------------- */

.btn--primary {
  background-color: var(--brand);
  color: var(--brand-ink);
}

.btn--primary:hover {
  background-color: var(--brand-hover);
  color: var(--brand-ink);
  box-shadow: var(--glow-brand);
}

.btn--accent {
  background-color: var(--accent);
  color: #fff;
}

.btn--accent:hover {
  background-color: var(--accent-hover);
  color: #fff;
  box-shadow: var(--glow-accent);
}

.btn--ghost {
  border-color: var(--line-strong);
  background-color: transparent;
  color: var(--text);
}

.btn--ghost:hover {
  border-color: var(--brand);
  background-color: var(--brand-soft);
  color: var(--text);
}

.btn--quiet {
  padding-inline: var(--sp-3);
  background-color: transparent;
  color: var(--text-muted);
}

.btn--quiet:hover {
  background-color: var(--bg-raised);
  color: var(--text);
}

/* --- Sizes -------------------------------------------------------------- */

.btn--sm {
  min-height: 36px;
  padding: var(--sp-1) var(--sp-4);
  font-size: var(--fs-xs);
}

.btn--lg {
  min-height: 52px;
  padding: var(--sp-3) var(--sp-8);
  font-size: var(--fs-body);
}

/* Square button for a lone icon, e.g. the hero search submit. */
.btn--icon {
  width: 44px;
  min-height: 44px;
  padding: 0;
  flex: 0 0 auto;
}

.btn--block {
  width: 100%;
}


/* ==========================================================================
   7. CARDS

   One base card plus modifiers. Later phases build the app tile, the ranked
   featured card and the app list row on top of this, rather than each
   inventing its own surface.
   ========================================================================== */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
  background-color: var(--card-bg);
  box-shadow: var(--edge-light);
  color: var(--text);
  /* Rank badges hang off the corner, so children must not be clipped. */
  overflow: visible;
}

.card__media {
  position: relative;
  border-radius: calc(var(--r-md) - 1px) calc(var(--r-md) - 1px) 0 0;
  overflow: hidden;
}

.card__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-3);
  min-width: 0;   /* lets long app names truncate instead of stretching */
}

.card__title {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: var(--lh-snug);
  color: var(--text);
}

.card__meta {
  margin: 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.card__footer {
  margin-top: auto;
  padding: var(--sp-3);
  padding-top: 0;
}

/* --- Interactive --------------------------------------------------------
   For cards that are entirely one link. Transitions stay on colour and
   transform only, never on layout properties. */
.card--interactive {
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}

.card--interactive:hover {
  background-color: var(--card-bg-hover);
  border-color: var(--card-border-hover);
  transform: translateY(-2px);
}

.card--interactive:focus-within {
  border-color: var(--brand);
}

/* --- Emphasis ----------------------------------------------------------- */

/* Featured / ranked content. The glow is what marks it as important. */
.card--featured {
  border-color: var(--card-border-hover);
  box-shadow: var(--edge-light), var(--glow-brand);
}

/* Translucent panel for use OVER imagery. Glass needs something visually
   complex behind it, otherwise it is just a flat box with a render cost —
   so this is the only glass surface in the system. */
.card--glass {
  border-color: var(--line-strong);
  background-color: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card--glass {
    background-color: var(--bg-surface);
  }
}

/* Truncate a long app name to one line while keeping the full value in the
   element's title attribute for hover and assistive tech. */
.card__title--truncate {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}


/* ==========================================================================
   7b. APP DIRECTORY CARDS

   Dense browse grid used by Latest Apps and the All Apps listing.
   Distinct from the deferred Phase 5 featured/ranked cards: no glow, no
   rank badge, no podium layout. Built for scanability and many items.

   Markup lives in HTML. JavaScript must not generate this grid.
   ========================================================================== */

.app-grid {
  --min: 16.5rem;   /* 1 col on phones, 2 from ~600px, 3 from ~900px, 4 from ~1200px */
}

.app-grid > li {
  display: flex;
}

.app-card {
  height: 100%;
}

/* One hit target for the whole card — the "View App" control is a span
   styled as a button so it is not a nested link. */
.app-card__hit {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  height: 100%;
  padding: var(--sp-4);
  color: inherit;
  text-decoration: none;
}

.app-card__hit:hover,
.app-card__hit:focus-visible {
  color: inherit;
  text-decoration: none;
}

.app-card__top {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

.app-card__identity {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.app-card__desc {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.app-card__facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-xs);
}

.app-card__facts dt {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.app-card__facts dd {
  margin: 0;
}

.app-card__cta {
  margin-top: auto;
  pointer-events: none;   /* the parent <a> is the control */
}


/* --- Directory toolbar (search / filter / sort) -------------------------
   Progressive enhancement. The form is hidden in HTML until JavaScript
   reveals it. Cards stay in the markup whether they match or not. */

.directory-toolbar {
  display: grid;
  gap: var(--sp-3);
  margin-bottom: var(--sp-6);
}

.directory-toolbar label {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  color: var(--text-dim);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.directory-toolbar input,
.directory-toolbar select {
  width: 100%;
  min-height: 44px;
  padding: var(--sp-2) var(--sp-3);
}

@media (min-width: 700px) {
  .directory-toolbar {
    grid-template-columns: minmax(0, 1.5fr) minmax(10rem, 1fr) minmax(10rem, 1fr);
    align-items: end;
  }
}

.directory-empty {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}


/* --- Rating -------------------------------------------------------------
   Unrated listings keep empty stars. Rated listings overlay a gold fill
   whose width is (score / 5), so 4.0 is 80% and 4.5 is 90%. */

.rating {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-xs);
}

.rating__stars {
  position: relative;
  display: inline-block;
  letter-spacing: 0.06em;
  color: var(--text-dim);
}

.rating__base,
.rating__fill {
  display: block;
  letter-spacing: 0.06em;
}

.rating__fill {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  white-space: nowrap;
  color: var(--star);
}

.rating[data-rated="true"] .rating__base {
  color: rgba(255, 194, 60, 0.22);
}


/* ==========================================================================
   7c. CATEGORY CARDS

   Static HTML links. No JavaScript. Used on the homepage and /categories/.
   Hover only changes surface colour — no motion beyond the shared duration.
   ========================================================================== */

.category-grid {
  --min: 15.5rem;
}

.category-grid > li {
  display: flex;
}

.category-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  padding: 0;
}

.category-card__hit {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--sp-4);
  flex: 1 1 auto;
  padding: var(--sp-4);
  color: inherit;
  text-decoration: none;
}

.category-card__hit:hover,
.category-card__hit:focus-visible {
  color: inherit;
  text-decoration: none;
}

.category-card__icon {
  display: block;
  width: 3.5rem;
  height: 3.5rem;
  flex: 0 0 auto;
  overflow: hidden;
  border-radius: var(--r-sm);
  background-color: var(--brand-soft);
}

.category-card__icon img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.category-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.category-card__name {
  margin: 0;
  font-size: var(--fs-h3);
  font-weight: 700;
  letter-spacing: var(--track-tight);
  color: var(--text);
}

.category-card__desc {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.category-card__download {
  position: relative;
  z-index: 1;
  width: calc(100% - (var(--sp-4) * 2));
  margin: 0 var(--sp-4) var(--sp-4);
}


/* ==========================================================================
   7d. APP DETAIL PAGE

   Reusable layout for /apps/<slug>/index.html. Duplicate the example at
   apps/example-app/ and swap the HTML; these classes stay as-is.

   Content lives in the HTML. JavaScript must not generate this page.
   ========================================================================== */

.breadcrumb {
  margin-bottom: var(--sp-4);
}

.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

.breadcrumb li + li {
  margin-top: 0;
}

.breadcrumb [aria-current="page"] {
  color: var(--text-muted);
}

/* --- Identity band ------------------------------------------------------ */

.app-hero__layout {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.app-hero__main {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-width: 0;
}

.app-hero__top {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
}

.app-hero__identity {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
}

.app-hero__identity h1 {
  margin-bottom: 0;
}

.app-hero__kicker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-xs);
}

.app-hero__lead {
  margin: 0;
}

.app-hero__actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.app-hero__actions .btn {
  width: 100%;
}

.app-hero__note {
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-xs);
  text-align: center;
}

@media (min-width: 700px) {

  .app-hero__layout {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-8);
  }

  .app-hero__actions {
    flex: 0 0 15.5rem;
    padding-top: var(--sp-1);
  }

  .app-hero__note {
    text-align: left;
  }
}

/* --- Facts -------------------------------------------------------------- */

.app-meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3) var(--sp-4);
  margin: 0;
}

.app-meta div {
  min-width: 0;
}

.app-meta dt {
  margin: 0 0 var(--sp-1);
  color: var(--text-dim);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.app-meta dd {
  margin: 0;
  color: var(--text);
  font-size: var(--fs-sm);
}

@media (min-width: 700px) {
  .app-meta {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* --- Body + aside ------------------------------------------------------- */

.app-detail {
  display: grid;
  gap: var(--sp-10);
}

.app-detail__body > * + * {
  margin-top: var(--sp-10);
}

.app-detail__panel {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-5);
}

.app-detail__panel .app-meta {
  grid-template-columns: 1fr;
}

.app-detail__panel .btn {
  width: 100%;
}

@media (max-width: 899px) {
  .app-detail__aside {
    display: none;
  }
}

@media (min-width: 900px) {

  .app-detail {
    grid-template-columns: minmax(0, 1fr) 18.5rem;
    align-items: start;
  }

  .app-detail__aside {
    position: sticky;
    top: calc(var(--header-h) + var(--sp-4));
  }
}

/* --- Screenshots -------------------------------------------------------- */

.app-shots {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(11.5rem, 70%);
  gap: var(--grid-gap);
  margin: 0;
  padding: 0 0 var(--sp-2);
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}

.app-shots > li {
  margin: 0;
  scroll-snap-align: start;
}

.app-shot {
  margin: 0;
}

.app-shot__frame {
  --ratio: 9 / 16;
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
  box-shadow: var(--edge-light);
}

.app-shot figcaption {
  margin-top: var(--sp-2);
  color: var(--text-dim);
  font-size: var(--fs-xs);
}

@media (min-width: 700px) {

  .app-shots {
    grid-auto-flow: row;
    grid-auto-columns: unset;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    overflow: visible;
    padding-bottom: 0;
  }
}

/* --- Feature / audience cards ------------------------------------------- */

.feature-grid {
  --min: 16rem;
}

.feature-grid > li {
  display: flex;
  margin-top: 0;
}

.feature-grid .card {
  width: 100%;
  height: 100%;
}

.feature-grid h3 {
  margin-bottom: var(--sp-2);
}

/* --- Numbered steps ----------------------------------------------------- */

.step-list {
  display: grid;
  gap: var(--grid-gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

.step-list > li {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-4);
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
  background-color: var(--card-bg);
  box-shadow: var(--edge-light);
}

.step-list__n {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  margin-bottom: var(--sp-1);
  border-radius: 50%;
  background-color: var(--brand-soft);
  color: var(--brand);
  font-size: var(--fs-xs);
  font-weight: 800;
}

.step-list h3 {
  margin: 0;
}

@media (min-width: 700px) {
  .step-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* --- Requirements ------------------------------------------------------- */

.req-list {
  display: grid;
  margin: 0;
  padding: 0;
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
  background-color: var(--card-bg);
  overflow: hidden;
}

.req-list > div {
  display: grid;
  grid-template-columns: minmax(8rem, 32%) 1fr;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
}

.req-list > div + div {
  border-top: 1px solid var(--line);
}

.req-list dt {
  margin: 0;
  color: var(--text-dim);
  font-weight: 600;
}

.req-list dd {
  margin: 0;
  color: var(--text);
}

/* --- FAQ accordion ------------------------------------------------------
   Buttons + panels. Without JavaScript the panels stay open in the HTML.
   JavaScript only toggles [hidden] and aria-expanded. */

.app-faq {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.app-faq__item {
  padding: var(--sp-4);
  border: 1px solid var(--card-border);
  border-radius: var(--r-md);
  background-color: var(--card-bg);
  box-shadow: var(--edge-light);
  transition: border-color var(--dur) var(--ease);
}

.app-faq__heading {
  margin: 0;
  font-size: var(--fs-sm);
}

.app-faq__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: inherit;
  font-weight: 700;
  line-height: var(--lh-snug);
  text-align: left;
  transition: color var(--dur) var(--ease);
}

.app-faq__trigger:hover {
  color: var(--brand);
}

.app-faq__trigger::after {
  content: "+";
  flex: 0 0 auto;
  color: var(--brand);
  font-weight: 700;
  line-height: 1;
}

.app-faq__trigger[aria-expanded="true"]::after {
  content: "\2212";
}

.app-faq__trigger[aria-expanded="true"] {
  margin-bottom: var(--sp-3);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
}

.app-faq__panel p:last-child {
  margin-bottom: 0;
}


/* ==========================================================================
   8. BADGES

   Small labels: ranks, categories, version flags. Each variant only sets
   two local custom properties, so adding a colour is a two-line change.
   ========================================================================== */

.badge {
  --badge-bg: var(--bg-raised);
  --badge-fg: var(--text-muted);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  padding: 0.2em 0.6em;
  border-radius: var(--r-pill);
  background-color: var(--badge-bg);
  color: var(--badge-fg);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
}

.badge--brand  { --badge-bg: var(--brand);       --badge-fg: var(--brand-ink); }
.badge--accent { --badge-bg: var(--accent);      --badge-fg: #fff; }
.badge--soft   { --badge-bg: var(--accent-soft); --badge-fg: var(--accent-hover); }
.badge--danger { --badge-bg: var(--danger);      --badge-fg: #2a0b0b; }

/* --- Rank badge ---------------------------------------------------------
   A circle that straddles a card's top-left corner so it reads as an
   applied sticker rather than a UI chip. The parent card must keep
   overflow visible, which .card already does.

   Medal tints carry the ordering, so the position is understandable even
   before the number is read. Ranks 4+ fall back to the neutral default. */
.badge--rank {
  position: absolute;
  top: calc(var(--sp-2) * -1);
  left: calc(var(--sp-2) * -1);
  z-index: var(--z-raised);
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-radius: 50%;
  box-shadow: var(--sh-1);
  font-variant-numeric: tabular-nums;
}

.badge--rank-1 { --badge-bg: var(--rank-1); --badge-fg: #2b1d00; }
.badge--rank-2 { --badge-bg: var(--rank-2); --badge-fg: #1a2027; }
.badge--rank-3 { --badge-bg: var(--rank-3); --badge-fg: #2a1405; }


/* ==========================================================================
   9. MEDIA & IMAGES
   ========================================================================== */

/* Fixed-ratio image box. Set --ratio per use; defaults to 16/9.
   Reserving the box prevents layout shift while the image loads. */
.media {
  position: relative;
  aspect-ratio: var(--ratio, 16 / 9);
  overflow: hidden;
  border-radius: var(--r-sm);
  background-color: var(--bg-raised);
}

.media > img,
.media > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- App icon -----------------------------------------------------------
   App artwork is always square with a proportional squircle radius. Locking
   both is what makes a grid of inconsistent third-party icons look
   deliberate. The hairline border keeps pale icons from bleeding into the
   card surface. */
.app-icon {
  aspect-ratio: 1 / 1;
  width: 100%;
  border-radius: var(--r-icon);
  border: 1px solid var(--line);
  background-color: var(--bg-raised);
  object-fit: cover;
}

.app-icon--sm {
  width: 4.5rem;
  flex: 0 0 auto;
}

.app-icon--lg {
  width: 5.5rem;
  flex: 0 0 auto;
}

@media (min-width: 700px) {
  .app-icon--lg {
    width: 7rem;
  }
}

/* Fills its parent while keeping the parent's own corner rounding. */
.img-cover {
  width: 100%;
  height: 100%;
  object-fit: cover;
}


/* ==========================================================================
   10. ANNOUNCEMENT BAR, SITE HEADER & PRIMARY NAVIGATION

   Mobile-first: the nav is a collapsible panel below the bar. From 900px up
   it becomes an inline row and the toggle button is removed.

   The nav links always exist in the HTML — they are only ever hidden with
   CSS, and the footer repeats them as plain visible links, so navigation is
   never dependent on JavaScript.
   ========================================================================== */

/* --- 10.1 Announcement bar ----------------------------------------------
   Scrolls away with the page; only .site-header is sticky. The descriptive
   sentence is hidden on narrow screens so the bar can never wrap or push
   the layout sideways — the link alone still carries the meaning. */

.topbar {
  background-color: var(--bg-band);
  background-image: var(--grad-topbar);
  border-bottom: 1px solid var(--line);
  color: var(--text-muted);
  font-size: var(--fs-xs);
}

.topbar__inner {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  padding-block: var(--sp-1);
}

.topbar__text {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1) var(--sp-3);
  margin: 0;
  text-align: center;
}

.topbar__link {
  color: var(--brand);
  font-weight: 700;
  white-space: nowrap;
}

.topbar__message {
  display: none;
}

@media (min-width: 560px) {
  .topbar__message {
    display: inline;
  }
}

/* --- 10.2 Header bar ---------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background-color: var(--bg-page);
  transition: background-color var(--dur) var(--ease);
}

/* Accent rule in place of a flat border, faded at both ends. Sits on the
   header's own bottom edge, so the nav panel below it is unaffected. */
.site-header::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 1px;
  background-image: var(--grad-underline);
  pointer-events: none;
}

/* .is-scrolled is added by js/main.js once the page scrolls. */
.site-header.is-scrolled {
  background-color: rgba(11, 15, 20, 0.85);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header.is-scrolled {
    background-color: var(--bg-page);
  }
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--header-h);
}

/* --- 10.3 Logo / brand --------------------------------------------------
   TO RENAME THE SITE: the brand appears in exactly two places per page —
   the header logo and the footer logo — as
   `Yono<span class="site-logo__accent">io</span>`. The accent span colours
   the tail of the word; split the new name wherever you want the colour to
   start, and update the matching aria-label. Page <title> and meta
   description hold the name too. */

.site-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--text);
  font-weight: 800;
  font-size: 1.0625rem;
  letter-spacing: var(--track-tight);
  text-decoration: none;
}

.site-logo:hover {
  color: var(--text);
  text-decoration: none;
}

.site-logo__mark {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  border-radius: var(--r-sm);
  background-image: var(--grad-brand);
  color: var(--brand-ink);
  font-size: 1rem;
  font-weight: 800;
}

.site-logo__text {
  white-space: nowrap;
}

.site-logo__accent {
  color: var(--brand);
}

/* --- 10.4 Nav toggle (mobile only) ------------------------------------- */

.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background-color: transparent;
}

.nav-toggle__bar {
  display: block;
  height: 2px;
  border-radius: 2px;
  background-color: var(--text);
  transition: transform var(--dur) var(--ease),
              opacity var(--dur) var(--ease);
}

/* The button has no other element children, so nth-child maps directly
   onto the three bars. Keep it that way: adding a child element here
   would shift these selectors. */
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* --- 10.5 Nav panel (mobile) / nav row (desktop) -----------------------
   The panel is absolutely positioned inside the sticky header, so opening
   it never reflows the page. It animates opacity and a small vertical
   nudge — `display` cannot be transitioned, which is why the closed state
   uses visibility instead.

   `visibility: hidden` also takes the links out of the tab order while
   closed, so keyboard focus cannot land on an invisible menu. The delayed
   visibility transition lets the fade-out finish before it is applied. */

.primary-nav {
  position: absolute;
  top: 100%;
  right: 0;
  left: 0;
  z-index: var(--z-nav-panel);
  background-color: var(--bg-surface);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--sh-2);

  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  pointer-events: none;
  transition: opacity var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              visibility 0s linear var(--dur);
}

.primary-nav.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
  transition: opacity var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              visibility 0s;
}

body.is-nav-open {
  overflow: hidden;
}

.primary-nav__list {
  margin: 0;
  padding: var(--sp-2) var(--gutter) var(--sp-4);
  list-style: none;
}

.primary-nav__list li + li {
  margin-top: 0;
}

.primary-nav__link {
  display: block;
  padding: var(--sp-3) var(--sp-2);
  border-bottom: 1px solid var(--line);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
}

.primary-nav__link:hover {
  color: var(--text);
  text-decoration: none;
}

/* aria-current="page" marks the active link in each page's HTML. */
.primary-nav__link[aria-current="page"] {
  color: var(--brand);
}

@media (min-width: 900px) {

  .nav-toggle {
    display: none;
  }

  /* Becomes an inline row. Every closed-panel property is reset here, so
     the nav is permanently visible regardless of the .is-open class. */
  .primary-nav {
    position: static;
    background-color: transparent;
    border-bottom: 0;
    box-shadow: none;

    opacity: 1;
    visibility: visible;
    transform: none;
    pointer-events: auto;
    transition: none;
  }

  .primary-nav__list {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    padding: 0;
  }

  .primary-nav__link {
    padding: var(--sp-2) 0.55rem;
    border-bottom: 0;
    border-radius: var(--r-pill);
    white-space: nowrap;
  }

  .primary-nav__link:hover {
    background-color: var(--bg-surface);
  }

  .primary-nav__link[aria-current="page"] {
    background-color: var(--brand-soft);
  }
}


/* ==========================================================================
   11. HERO

   Four stacked layers, back to front:

     .hero__media   background artwork (decorative <picture>)
     .hero__scrim   flat dark wash — the readability guarantee
     .hero__glow    brand/accent radial gradients for depth
     .hero__inner   heading, paragraph and search pill

   Mobile is NOT the desktop hero scaled down. Below 600px the hero switches
   to the portrait image crop, a heavier scrim, a tighter vertical rhythm and
   an icon-only search button. Height follows the text and search, so the
   next homepage section can sit above the fold on phones and desktops.
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;         /* also the last line of defence against any
                               horizontal overflow from the search row */
  display: grid;
  align-content: center;
  border-bottom: 1px solid var(--line-accent);
  background-color: var(--bg-band);   /* shows while the artwork decodes */
  text-align: center;
  min-height: 0;
}

/* --- Layer 1: artwork ---------------------------------------------------- */

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -3;
}

.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Portrait crop: keep the teal bloom in the upper half, dark floor below. */
  object-position: 50% 22%;
  background-color: var(--bg-band);
}

/* --- Layer 2: dark wash -------------------------------------------------- */

.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image: var(--hero-scrim-strong);
}

/* --- Layer 3: brand glow ------------------------------------------------- */

.hero__glow {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--hero-glow);
}

/* --- Layer 4: content ---------------------------------------------------- */

.hero__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding-block: var(--sp-6);
}

/* Small capsule above the H1. Decorative framing for real text. */
.hero__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-1) var(--sp-4);
  border: 1px solid var(--line-accent);
  border-radius: var(--r-pill);
  background-color: var(--brand-soft);
  color: var(--brand);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.hero__eyebrow::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background-color: var(--brand);
}

.hero__title {
  max-width: 26ch;
  margin-bottom: 0;
  font-size: var(--fs-hero);
  /* Lifts the heading off a busy background without faking a glow. */
  text-shadow: 0 2px 20px rgba(3, 6, 10, 0.6);
}

.hero__text {
  max-width: 48ch;
  margin-bottom: 0;
  font-size: var(--fs-sm);
}

.hero__hint {
  margin-bottom: 0;
  color: var(--text-dim);
  font-size: var(--fs-sm);
}

@media (max-width: 599px) {
  .hero__hint {
    display: none;
  }
}

.hero__hint a {
  color: var(--text-muted);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

.hero__hint a:hover {
  color: var(--brand);
}

/* --- Layer 5: search pill ------------------------------------------------
   The input and the submit button share one pill so they read as a single
   control. No JavaScript is required for it to work. */

.hero-search {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  max-width: 32rem;
  margin-block-start: 0;
  padding: var(--sp-1);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--r-pill);
  /* Light pill on a dark cinematic field — the search is the visual anchor. */
  background-color: var(--hero-search-bg);
  box-shadow: var(--sh-3);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .hero-search {
    -webkit-backdrop-filter: blur(var(--glass-blur));
    backdrop-filter: blur(var(--glass-blur));
    background-color: var(--hero-search-bg-frost);
  }
}

/* The focus ring goes on the pill, because the input inside it has no border
   of its own to highlight. */
.hero-search:focus-within {
  border-color: var(--brand);
  box-shadow: var(--glow-brand), var(--sh-3);
}

.hero-search__input {
  flex: 1 1 auto;
  /* Without this the input keeps its default intrinsic width and pushes the
     button out of the pill on narrow phones. */
  min-width: 0;
  min-height: 44px;
  padding-inline: var(--sp-5);
  border: 0;
  border-radius: var(--r-pill);
  background-color: transparent;
  color: var(--bg-page);
  /* Stays at 16px: anything smaller makes iOS Safari zoom on focus. */
  font-size: var(--fs-body);
  text-align: left;
}

.hero-search__input::placeholder {
  color: var(--hero-search-placeholder);
  opacity: 1;
}

.hero-search__input:focus-visible {
  outline: none;
}

.hero-search__input::-webkit-search-decoration,
.hero-search__input::-webkit-search-cancel-button {
  -webkit-appearance: none;
}

/* Icon-only on phones, labelled from 600px up. */
.hero-search__submit {
  flex: 0 0 auto;
  width: 44px;
  padding-inline: 0;
}

.hero-search__label {
  display: none;
}

/* --- 600px and up: landscape crop, lighter scrim, labelled button -------- */

@media (min-width: 600px) {

  .hero__media img {
    object-position: 50% 38%;
  }

  .hero__scrim {
    background-image: var(--hero-scrim);
  }

  .hero__inner {
    gap: var(--sp-4);
    padding-block: var(--sp-8);
  }

  .hero-search__submit {
    width: auto;
    padding-inline: var(--sp-5);
  }

  .hero-search__label {
    display: inline;
  }
}

/* --- 900px and up: compact desktop composition -------------------------- */

@media (min-width: 900px) {

  .hero__inner {
    gap: var(--sp-4);
    padding-block: var(--sp-8) var(--sp-10);
  }

  /* Two strong lines rather than one very long one. */
  .hero__title {
    max-width: 20ch;
  }

  .hero-search {
    max-width: 34rem;
  }
}

/* Interior-page hero: shorter, left-aligned, no imagery. */
.page-hero {
  padding-block: clamp(var(--sp-8), 6vw, var(--sp-12));
  background-color: var(--bg-band);
  border-bottom: 1px solid var(--line);
  text-align: left;
}


/* ==========================================================================
   12. SECTION HEADINGS

   Shared heading row: title on the left, optional "view all" link on the
   right, hairline underneath. Used by every content section so the vertical
   rhythm stays consistent.
   ========================================================================== */

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-bottom: var(--sp-3);
  margin-bottom: var(--sp-6);
  border-bottom: 1px solid var(--line);
}

.section-head__title {
  margin-bottom: 0;
}

.section-head__link {
  flex: 0 0 auto;
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
}


/* ==========================================================================
   13. PLACEHOLDER BLOCKS — TEMPORARY SCAFFOLDING

   These mark where real components will go. Delete each one as its real
   component is built, and delete this whole section once none remain.
   ========================================================================== */

.placeholder {
  display: grid;
  place-items: center;
  gap: var(--sp-2);
  min-height: 140px;
  padding: var(--sp-6) var(--sp-4);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background-color: var(--bg-surface);
  box-shadow: var(--edge-light);
  color: var(--text-dim);
  font-size: var(--fs-sm);
  text-align: center;
}

.placeholder__label {
  color: var(--text-muted);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: var(--fs-xs);
}

.placeholder p {
  max-width: 52ch;
  margin-bottom: 0;
}

/* Quiet reserved slot. Used only to hold the page location of a deferred
   section (currently Phase 5). No cards, copy or chrome. Collapsed while
   empty so the compact hero can keep the next real section above the fold. */
#trending:has(.phase-reserved) {
  padding-block: 0;
  border-block: 0;
  background-color: transparent;
}

.phase-reserved {
  min-height: 0;
}


/* ==========================================================================
   14. SITE FOOTER
   ========================================================================== */

.site-footer {
  padding-block: var(--section-y) var(--sp-6);
  background-color: var(--bg-band);
  border-top: 1px solid var(--line);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.site-footer__grid {
  display: grid;
  gap: var(--sp-8);
  grid-template-columns: 1fr;
  padding-bottom: var(--sp-8);
}

@media (min-width: 600px) {
  .site-footer__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 900px) {
  .site-footer__grid {
    grid-template-columns: 1.4fr repeat(3, 1fr);
  }
}

.site-footer__heading {
  margin-bottom: var(--sp-3);
  color: var(--text);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.site-footer__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__list li + li {
  margin-top: var(--sp-2);
}

.site-footer__list a {
  color: var(--text-muted);
}

.site-footer__list a:hover {
  color: var(--brand);
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--line);
  color: var(--text-dim);
  font-size: var(--fs-xs);
}

.site-footer__bottom p {
  margin-bottom: 0;
}


/* ==========================================================================
   15. REDUCED MOTION & PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {

  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .card--interactive:hover {
    transform: none;
  }
}

@media print {

  .site-header,
  .site-footer,
  .skip-link,
  .placeholder,
  .hero__media,
  .hero__scrim,
  .hero__glow,
  .hero-search {
    display: none;
  }

  /* Hero keeps its text, loses its cinematic staging. */
  .hero {
    min-height: 0;
    border-bottom: 0;
  }

  body {
    background: #fff;
    color: #000;
  }

  .card {
    border-color: #ccc;
    box-shadow: none;
  }
}
