/* Index page for the Rozalix sample-work collection.
 *
 * Every sample on this page arrives with its own strong accent, so the page is
 * already near its noise budget before a single decorative element is added —
 * and it gets tighter with each one added. The frame therefore does almost
 * nothing: white ground, one indigo for Rozalix's own moments, hairlines
 * instead of boxes, and a great deal of empty space. The colour on this page
 * belongs to the work.
 *
 * The two things the frame is allowed to build are the ones nobody else can
 * claim: the assistant answering in the hero, and the range strip that puts
 * every accent on screen at once. */

:root {
  --paper: #FFFFFF;
  --ink: #0F172A;
  --ink-soft: #475569;
  --muted: #94A3B8;
  --line: #E2E8F0;
  --tint: #F8FAFC;
  --indigo: #4F46E5;
  --violet: #7C3AED;

  /* 56px of margin at full width, matching the reference proportions. */
  --shell: min(1320px, 100% - 7rem);

  /* Sections are far apart on purpose. The scroll is meant to have rests in
     it; a page of work this loud needs somewhere for the eye to stop. */
  --gap: clamp(5rem, 4rem + 5vw, 10rem);
}

@media (max-width: 1079px) { :root { --shell: min(1320px, 100% - 4rem); } }
@media (max-width: 699px)  { :root { --shell: min(1320px, 100% - 2.5rem); --gap: 5rem; } }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

.mono {
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

a { color: inherit; }

:focus-visible {
  outline: 2.5px solid var(--indigo);
  outline-offset: 3px;
  border-radius: 4px;
}

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

.h2 {
  margin: 0;
  font-size: clamp(1.75rem, 1rem + 1.6vw, 2.375rem);
  line-height: 1.05;
  letter-spacing: -0.025em;
  font-weight: 600;
}

/* ---------- header ---------- */

/* No call to action up here. The widget is on screen the whole time and the
   closer has both ways on; a third button would be the frame talking. */
.top {
  width: var(--shell);
  margin: 0 auto;
  padding: 1.75rem 0 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

/* The lockup as it is drawn everywhere else: mark and wordmark at the same
   1.4 : 1 ratio the landing nav uses, scaled down for a quieter header. The
   mark is not set in a tile here — a filled indigo square is a second block of
   brand colour, and this page has fourteen other brands to make room for. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.56rem;
  text-decoration: none;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-size: 1.25rem;
}

.brand__mark {
  width: 28px;
  height: 28px;
  flex: none;
  color: var(--indigo);
}

.top__meta {
  margin: 0;
  font-size: 0.655rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: right;
}

/* ---------- hero ---------- */

.hero {
  width: var(--shell);
  margin: 0 auto;
  padding-top: clamp(3rem, 1rem + 5vw, 6rem);
  display: grid;
  gap: clamp(2.5rem, 4vw, 3.5rem);
  align-items: end;
}

@media (min-width: 1080px) {
  .hero { grid-template-columns: minmax(0, 1fr) minmax(0, 440px); }
  .hero__show { justify-self: end; }
}

.hero__title {
  margin: 0;
  font-size: clamp(2.5rem, 1.2rem + 4.4vw, 4.75rem);
  line-height: 0.98;
  letter-spacing: -0.035em;
  font-weight: 600;
  max-width: 13ch;
  text-wrap: balance;
}

.hero__lead {
  margin: 1.75rem 0 0;
  max-width: 34em;
  font-size: 1.0625rem;
  line-height: 1.55;
  color: var(--ink-soft);
}

/* Only pulled to the right once it has a column of its own. Chrome honours
   justify-self in block layout now, so leaving it set collapsed the panel
   against the right edge under a full-width headline at tablet size. */
.hero__show { width: 100%; max-width: 440px; }

.hero__caption {
  margin: 0.7rem 0 0;
  font-size: 0.625rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.7;
}

/* ---------- the widget, demonstrated ---------- */

.demo {
  --a: var(--indigo);
  --a-wash: #EEF0FE;
  --a-edge: #C7CBF7;
  --a-fg: var(--ink);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 18px 44px -28px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.demo__bar {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.8rem 0.95rem;
  border-bottom: 1px solid var(--line);
  background: var(--tint);
}

.demo__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--a);
  flex: none;
  animation: demo-pulse 1.9s ease-in-out infinite;
}

@keyframes demo-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.82); }
}

.demo__brand { font-weight: 600; font-size: 0.845rem; }

.demo__state {
  margin-left: auto;
  font-size: 0.595rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Held at a fixed height so the panel does not grow and shrink under the
   headline every few seconds while the conversations cycle. */
.demo__thread {
  padding: 1rem 0.95rem;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.55rem;
  min-height: 236px;
}

.bub { display: flex; }
.bub--me { justify-content: flex-end; }

.bub__t {
  max-width: 82%;
  padding: 0.55rem 0.75rem;
  font-size: 0.845rem;
  line-height: 1.45;
  border: 1px solid;
  border-radius: 12px 12px 12px 3px;
}

.bub--me .bub__t {
  border-radius: 12px 12px 3px 12px;
  background: var(--tint);
  border-color: var(--line);
  color: var(--ink);
}

.bub--bot .bub__t {
  background: var(--a-wash);
  border-color: var(--a-edge);
  color: var(--a-fg);
}

/* ---------- range strip ---------- */

.range {
  width: var(--shell);
  margin: 0 auto;
  padding-top: var(--gap);
}

.range__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-bottom: 1.9rem;
}

.range__legend {
  margin: 0;
  font-size: 0.625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.range__scale {
  display: flex;
  align-items: flex-end;
  gap: clamp(0.9rem, 1.8vw, 1.65rem);
  overflow-x: auto;
  padding-bottom: 4px;
}

.range__group { flex: 1 1 0; min-width: calc(var(--n, 1) * 34px); }

.range__bars {
  display: flex;
  align-items: flex-end;
  gap: 5px;
  height: 84px;
}

/* Height is build depth, colour is the brand. Both are facts off the list, so
   the strip cannot drift out of step with the grid below it.
   The width is capped: left to fill their column the bars came out wider than
   they were tall, which reads as a swatch book — the one thing this page must
   not look like — and buried the height difference that carries the meaning. */
.range__bar {
  flex: 1 1 0;
  min-width: 0;
  max-width: 42px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: var(--a);
  cursor: pointer;
  transition: transform 0.16s ease;
}
.range__bar:hover { transform: translateY(-4px); }

.range__cat {
  margin: 0.55rem 0 0;
  border-top: 1px solid var(--line);
  padding-top: 0.5rem;
  font-size: 0.6rem;
  letter-spacing: 0.06em;
  line-height: 1.4;
  color: var(--ink);
}

/* ---------- the work ---------- */

.work {
  width: var(--shell);
  margin: 0 auto;
  padding-top: var(--gap);
  scroll-margin-top: 1.5rem;
}

.work__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-bottom: 1.4rem;
}

.work__shown { margin: 0; font-size: 0.68rem; color: var(--muted); }

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-bottom: clamp(2.25rem, 3.5vw, 3rem);
}

.chip {
  font: inherit;
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.69rem;
  letter-spacing: 0.02em;
  padding: 0.5rem 0.8rem;
  border-radius: 999px;
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--line);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.chip:hover { border-color: var(--muted); }
.chip.is-on { background: var(--ink); border-color: var(--ink); color: #fff; }

/* A mosaic rather than a uniform grid: the samples are not equivalent and a
   row of identical tiles says they are. Widths vary; the aspect ratio does not,
   because these are real screenshots and cropping them into portrait tiles
   throws away the layout that is the entire point of showing them. */
.cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-auto-flow: dense;
  align-items: start;
  column-gap: clamp(1.5rem, 2.2vw, 1.75rem);
  row-gap: clamp(2.5rem, 4vw, 3.75rem);
}

.card[data-span="2"] { grid-column: span 2; }
.card[data-span="3"] { grid-column: span 3; }
.card[data-span="4"] { grid-column: span 4; }

/* Filtered down to one trade there is no mosaic to make — two or three cards
   at mixed widths just look like a mistake. */
.cards.is-filtered .card { grid-column: span 3; }

@media (max-width: 1079px) {
  .cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .card[data-span="2"], .card[data-span="3"] { grid-column: span 2; }
  .card[data-span="4"] { grid-column: span 4; }
  .cards.is-filtered .card { grid-column: span 2; }
}

@media (max-width: 699px) {
  .cards { grid-template-columns: 1fr; row-gap: 2.75rem; }
  /* Has to out-specify .card[data-span="…"], or a span survives into the
     one-column grid, opens an implicit second column and every card lands on
     top of its neighbour. */
  .cards .card[data-span],
  .cards.is-filtered .card { grid-column: auto; }
  .card__shot { aspect-ratio: var(--ratio-phone, 4 / 3); }
}

.card__link { display: block; text-decoration: none; color: inherit; }

/* The tile is the only boxed thing on the card. The words below sit straight
   on the page ground — a border around them would add a fifteenth rectangle to
   a page that already has fourteen. */
.card__shot {
  display: block;
  position: relative;
  /* Set per card by the renderer: portrait for narrow columns, landscape for
     wide ones, one shared ratio once real screenshots go back in. */
  aspect-ratio: var(--ratio, 4 / 3);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--tint);
  /* The brand's accent as a hairline under its screenshot — enough to tie the
     card to its work without the frame picking up fourteen colours of its own.
     Under, not over: a bar across the top of a real screenshot sits on the
     sample's own header. */
  box-shadow: inset 0 -3px 0 var(--a, transparent);
  transition: border-color 0.2s ease;
}

.card__link:hover .card__shot { border-color: var(--a); }

.card__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.card__link:hover .card__shot img { transform: scale(1.02); }

/* The empty slot. It has no picture to be quiet behind, so the accent runs
   across the top at full strength and the hatch tells you the tile is a
   reservation rather than a design. */
.card__shot--slot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px;
  color: var(--a);
  box-shadow: inset 0 4px 0 var(--a);
}

.card__shot--slot::before,
.card__shot--slot::after {
  content: "";
  position: absolute;
  inset: 0;
}
.card__shot--slot::before { background: currentColor; opacity: 0.07; }
.card__shot--slot::after {
  background-image: repeating-linear-gradient(135deg, currentColor 0 1px, transparent 1px 10px);
  opacity: 0.28;
}

/* Positioned so they paint over the two absolutely-positioned washes above —
   in-flow content alone would sit underneath them. */
.card__chip {
  position: relative;
  font-size: 0.595rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.86);
  padding: 5px 7px;
  border-radius: 4px;
}

.card__chip--flavour { color: var(--a); }

.card__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin-top: 0.9rem;
}

.card__name { font-size: 1.125rem; font-weight: 600; letter-spacing: -0.015em; }

.card__cat {
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.card__line {
  display: block;
  margin-top: 0.4rem;
  max-width: 44em;
  font-size: 0.905rem;
  line-height: 1.55;
  color: var(--ink-soft);
}

.card__build {
  display: inline-block;
  margin-top: 0.65rem;
  padding-bottom: 1px;
  font-size: 0.625rem;
  letter-spacing: 0.05em;
  color: var(--ink);
  border-bottom: 2px solid var(--a);
}

.card__ask {
  display: block;
  margin-top: 0.65rem;
  font-size: 0.625rem;
  letter-spacing: 0.03em;
  line-height: 1.5;
  color: var(--muted);
}

.empty { margin: 2rem 0 0; color: var(--muted); font-size: 0.92rem; }

/* ---------- closer ---------- */

.closer {
  width: var(--shell);
  margin: 0 auto;
  padding-top: var(--gap);
}

@media (min-width: 1080px) {
  .closer {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 400px);
    gap: 3.5rem;
    align-items: center;
  }
}

.closer__title {
  margin: 0;
  font-size: clamp(2.5rem, 1.2rem + 4.4vw, 4.75rem);
  line-height: 1;
  letter-spacing: -0.035em;
  font-weight: 600;
  max-width: 9ch;
  text-wrap: balance;
}

.closer__lead {
  margin: 1.5rem 0 0;
  max-width: 30em;
  font-size: 1.0625rem;
  line-height: 1.55;
  color: var(--ink-soft);
}

.closer__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.9rem;
}

.btn {
  font: inherit;
  font-size: 0.905rem;
  font-weight: 500;
  border-radius: 8px;
  padding: 0.8rem 1.25rem;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  border: 1px solid transparent;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.btn--primary { background: var(--indigo); color: #fff; }
.btn--primary:hover { background: var(--violet); }

.btn--ghost { background: #fff; color: var(--ink); border-color: var(--line); }
.btn--ghost:hover { border-color: var(--ink); }

.closer__slot {
  width: 100%;
  max-width: 400px;
  aspect-ratio: 4 / 3;
  border: 1px dashed var(--muted);
  border-radius: 8px;
  background: var(--tint);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 1rem;
  margin-top: 2.5rem;
}

@media (min-width: 1080px) { .closer__slot { margin-top: 0; justify-self: end; } }

.closer__slot-tag { font-size: 0.69rem; letter-spacing: 0.1em; color: var(--indigo); }

.closer__slot-line {
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.7;
}

/* ---------- footer ---------- */

.foot {
  width: var(--shell);
  margin: var(--gap) auto 0;
  border-top: 1px solid var(--line);
  padding: 1.4rem 0 3.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
}

.foot p {
  margin: 0;
  font-size: 0.625rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  max-width: 52em;
  line-height: 1.8;
}
.foot a { text-decoration-color: var(--line); text-underline-offset: 2px; }
.foot a:hover { color: var(--indigo); }

/* ---------- small screens ---------- */

@media (max-width: 699px) {
  .top { flex-direction: column; align-items: flex-start; gap: 0.6rem; }
  .top__meta { text-align: left; }
  .hero__show { max-width: none; }
  .range__head { margin-bottom: 1.4rem; }
  /* Wrapped rather than scrolled. A sideways scroller cut two of the seven
     trades off the phone screen, and a strip whose whole argument is "look how
     many different registers there are" cannot end mid-swatch. */
  .range__scale { flex-wrap: wrap; overflow-x: visible; column-gap: 0.9rem; row-gap: 1.4rem; }
  /* Fixed thirds, not flex-grow: a last row holding one group would otherwise
     stretch it to full width and hang a long rule under two small bars. */
  .range__group { flex: 0 1 calc(33.333% - 0.6rem); min-width: 0; }
  .closer__actions .btn { flex: 1 1 auto; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .demo__dot { animation: none; }
  .card__shot, .card__shot img, .range__bar, .btn, .chip { transition: none; }
  .card__link:hover .card__shot img { transform: none; }
  .range__bar:hover { transform: none; }
}
