/**
 * Browse screen composition.
 *
 * Two columns at the draft's 1.38:1 ratio (its left content spanned 158px, its
 * right 114px), used consistently by all three regions.
 *
 * The screen is organised around the dial's centre line, not as a single grid.
 * The dial fills the frame and takes its centre at 50% of the frame height, so
 * that same 50% is the axis everything else is placed against:
 *
 *     .browse__upper   times and note, above
 *     .browse__axis    year and date, centred ON the axis
 *     .browse__lower   media still, below
 */

.browse {
  /* Shared by every region, so the columns line up down the screen. */
  --edge-l: max(var(--gutter), var(--sal));
  --edge-r: max(var(--gutter), var(--sar));

  /*
   * How far the date readout reaches below the axis: half its display row,
   * the gap, and the languages line. Derived rather than measured, so the
   * still stays clear of it when the type scale changes.
   */
  --axis-below: calc(var(--fs-display-lg) / 2 + var(--space-sm) + var(--fs-sm) * 1.2);

  padding-top: max(var(--space-2xl), calc(var(--sat) + var(--space-md)));
  padding-bottom: calc(var(--bar-space) + var(--space-md));
  padding-left: var(--edge-l);
  padding-right: var(--edge-r);
}

/* The three regions share one column definition. */
.browse__upper,
.browse__axis,
.browse__lower {
  display: grid;
  grid-template-columns: 1.38fr 1fr;
  column-gap: var(--gutter);
}

/* The dial draws full-bleed beneath the content. */
.browse__dial {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.browse__content {
  position: relative;
  z-index: 1;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /*
   * Load-bearing. The dial's drag surface sits underneath this content, and
   * the draft placed the year and time readouts directly on top of it. Without
   * this, a drag begun on the year numerals is absorbed by the text and the
   * dial silently ignores it. Controls opt back in below.
   */
  pointer-events: none;
}

.browse__content button {
  pointer-events: auto;
}

/* ---- Back to the landing ---- */

.browse__back {
  flex: none;
  align-self: center;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  cursor: pointer;
}

/* The landing's descend cue, reversed -- the faint stem trails below and the
   solid head points back up, so the pair reads as one gesture and its undo. */
.browse__back svg {
  transform: rotate(180deg);
}

/* ---- Grid ---- */

/**
 * Above the axis. The draft's large gap between the times and the date display
 * is no longer a spacer row -- it falls out of the axis being pinned to 50%.
 */
.browse__upper {
  flex: none;
  margin-top: clamp(8px, 2vh, 24px);
  grid-template-areas: 'time note';
}

/**
 * The wheel's readout, pinned to the dial's centre line.
 *
 * left/right are 0 because an absolutely positioned element resolves against
 * its ancestor's padding box, so the screen's own padding does not apply here;
 * the same edge values are re-applied directly.
 */
.browse__axis {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  padding-left: var(--edge-l);
  padding-right: var(--edge-r);
  align-items: center;
  /* Sits over the dial's drag surface; it holds no controls. */
  pointer-events: none;
}

/**
 * Below the axis, clearing the date readout's descent.
 *
 * The still sits at the foot of this region, inset from the bottom by the same
 * amount as the right gutter so the two gaps read as a pair. The floor is the
 * home-indicator inset: matching the gutter exactly on a device that has one
 * would put a tappable element inside the system's swipe area, where the first
 * touch can be swallowed. On devices without an indicator the two gaps are
 * identical.
 */
.browse__lower {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  top: calc(50% + var(--axis-below) + var(--space-2xl));
  bottom: max(var(--edge-r), var(--sab));
  padding-left: var(--edge-l);
  padding-right: var(--edge-r);
  align-content: end;
  pointer-events: none;
  /* Lets the still size itself against this region -- see below. */
  container-type: size;

  /*
   * The still's long edge. Both orientations draw the same rectangle, so this
   * is the vertical still's height and the horizontal still's width.
   *
   * Driven by the region's HEIGHT, not by the second column. Sizing it from the
   * column made the still a function of frame width alone, so a tall screen --
   * which has proportionally more room below the axis -- got the same picture
   * as a short one and left up to a third of the region empty. Taking 85% of
   * the region instead lets it grow with the space that is actually there.
   *
   * 85% is calibrated so a 375x667 keeps the size it has today, and the
   * remaining 15% is what guarantees clearance from the date readout above:
   * the still is bottom-anchored, so it can never reach the region's top edge.
   *
   * The width term is the one that binds on tall screens. Height alone let the
   * still keep growing with the frame: on a 390x844 the landscape variant
   * reached 70% of the frame's width against 56% on a 375x667, which reads as
   * oversized rather than generous. So the long edge is capped at 66% of the
   * FRAME's width, which holds that proportion steady from h:w ~1.86 upward.
   *
   * Frame width is reconstructed rather than read: this container is inset by
   * the two edges, so 100cqw is the content box -- about 87% of the frame, and
   * not a fixed fraction of it, since the gutter's own clamp flattens at both
   * ends. Adding the edges back makes the 66% mean what it says, and keeps it
   * true in landscape, where a safe-area inset widens an edge past the gutter.
   *
   * A 375x667 is unaffected: its region is short enough that the height term
   * binds first, so the still keeps the size it was tuned to.
   */
  --still-long: min(
    calc(100cqh * 0.85),
    calc((100cqw + var(--edge-l) + var(--edge-r)) * 0.66)
  );
}

.browse__lower button {
  pointer-events: auto;
}

/* ---- Stream times ---- */

.browse__time {
  grid-area: time;
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  /* The draft indents this past the gutter, clear of the dial's inner ring. */
  padding-inline-start: var(--space-xl);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

.browse__time-row {
  display: flex;
  align-items: center;
  gap: 4px;
  line-height: 1.1;
}

.browse__time-row svg {
  flex: none;
  color: var(--text-dim);
}

.browse__clock {
  font-size: var(--fs-display-sm);
  letter-spacing: var(--track-normal);
}

.browse__meridiem {
  font-size: var(--fs-sm);
  letter-spacing: var(--track-wider);
  color: var(--text-faint);
}

/* ---- Note card ---- */

.browse__note {
  grid-area: note;
  align-self: start;
  min-width: 0;
  background: var(--surface-raised);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-2xl);
  /* Side padding trimmed from --space-lg to buy back measure for the larger
     type; the title is nowrap and would otherwise clip on a 375-wide screen. */
  padding: var(--space-lg) var(--space-md) var(--space-xl);
  box-shadow: var(--shadow-card);
  /* Height is bounded by the body's line clamp rather than a max-height, so
     the cut always lands between lines. */
}

.browse__note-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

/*
 * Now a clip's start timecode, so it takes the monospace face every other
 * timecode in the app uses. Truncates rather than pushing past the card edge.
 */
.browse__note-title {
  margin: 0;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xl);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: var(--track-normal);
  color: #fff;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * Streams carrying no clips fall back to a mock note. Dimmed so it is obvious
 * at a glance which cards are showing real data while wiring is in progress.
 */
.browse__note.is-mock .browse__note-title {
  color: var(--text-faint);
}

.browse__note-mark {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  color: var(--on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

/**
 * Truncated by line count, so the cut lands between lines with an ellipsis
 * rather than slicing through one.
 *
 * Eight lines puts the card within a pixel of the media still's height on a
 * 390-wide screen -- close enough to read as a pair without being pinned to
 * it. Real summaries are Chinese, which wraps at roughly one character per em,
 * so that is about 69 characters; the median summary fits, the long tail
 * ellipses.
 *
 * Short screens drop to six: eight would leave the card almost touching the
 * date readout on a 375x667, where there is only ~224px between the two.
 */
.browse__note-body {
  margin: var(--space-sm) 0 0;
  font-size: var(--fs-lg);
  line-height: 1.55;
  color: var(--text-secondary);
  text-wrap: pretty;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 8;
  line-clamp: 8;
  overflow: hidden;
}

@media (max-height: 700px) {
  .browse__note-body {
    -webkit-line-clamp: 6;
    line-clamp: 6;
  }
}

/* ---- Year ---- */

/* Column 1 of the axis. align-items:center puts the box on the centre line. */
.browse__year {
  grid-column: 1;
}

.browse__year-box {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1;
  color: var(--accent);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-md);
  padding: 7px 11px;
  font-variant-numeric: tabular-nums;
}

/* ---- Date ---- */

/**
 * Column 2 of the axis.
 *
 * Its height is only the display row, because the languages line is taken out
 * of flow below. That is what makes align-items:center centre the numerals on
 * the axis rather than the block's midpoint -- the draft centres the mmdd row
 * exactly on y=360 and lets the languages hang past it.
 */
.browse__date {
  position: relative;
  grid-column: 2;
  min-width: 0;
}

.browse__date-row {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.browse__monthday {
  font-family: var(--font-mono);
  font-size: var(--fs-display-lg);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--track-normal);
  color: #fff;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/**
 * Separator between month and day.
 *
 * Monospace gives every glyph a 0.6em cell, which is far too much air around a
 * middot and pushes the block past its column on narrow phones. The negative
 * margins pull the cell to ~0.34em; the glyph's own ink is a small centred dot,
 * so nothing collides.
 */
.browse__monthday-sep {
  margin-inline: -0.13em;
  color: var(--text-faint);
}

.browse__weekday {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 500;
  /* Explicit, because vertical text's line-height IS its width, and the date
     block's fit depends on it. */
  line-height: 1;
  letter-spacing: var(--track-vertical);
  color: var(--text-faint);
  writing-mode: vertical-rl;
  text-orientation: mixed;
  display: flex;
  align-items: center;
  align-self: stretch;
}

/*
 * The draft set this at 13px in a 114px column, where the longest language set
 * overflows. Stepped down and allowed to truncate so it cannot clip.
 */
/*
 * Hangs below the display row, out of flow, so it does not shift the numerals
 * off the axis. line-height is explicit because --axis-below depends on it.
 */
.browse__langs {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: var(--space-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.2;
  letter-spacing: var(--track-wide);
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

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

/**
 * Anchored to the bottom-right of the region. Both orientations share that
 * corner and the same rectangle -- only its rotation differs.
 */
.browse__still {
  grid-column: 1 / -1;
  align-self: end;
  justify-self: end;
  position: relative;
  width: calc(var(--still-long) * 114 / 188);
  aspect-ratio: 114 / 188;
  padding: 0;
  border: 0;
  background: none;
  border-radius: var(--radius-xl);
  overflow: hidden;
  cursor: pointer;
  box-shadow: var(--shadow-media), var(--ring-accent);
}

.browse__still-art {
  position: absolute;
  inset: 0;
  /* Stand-in for a real thumbnail; angle varies per stream. */
  background: linear-gradient(var(--still-angle, 160deg), #3a3a34, #17171a 55%, #26262c);
}

/* Fades in over the gradient, so a missing or slow poster shows tone rather
   than a hole. */
.browse__still-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity var(--dur-ui) var(--ease-out);
}

.browse__still-img.is-loaded {
  opacity: 1;
}

.browse__still-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(10, 10, 9, 0.25),
    rgba(10, 10, 9, 0) 40%,
    rgba(10, 10, 9, 0.45)
  );
}

.browse__still-tc {
  position: absolute;
  left: 10px;
  top: 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: 500;
  letter-spacing: 0.05em;
  color: var(--accent);
  background: rgba(10, 10, 9, 0.8);
  border-radius: var(--radius-pill);
  padding: 4px 7px;
}

.browse__still-play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
}

.browse__still-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 10px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: 500;
  letter-spacing: 0.05em;
  color: rgba(255, 255, 255, 0.75);
}

/**
 * The same rectangle turned on its side: width and height swap, and the
 * bottom-right corner stays put.
 */
.browse__lower[data-orientation='horizontal'] .browse__still {
  width: var(--still-long);
  aspect-ratio: 188 / 114;
}

/* ---- Loading ---- */

.browse.is-loading .browse__note,
.browse.is-loading .browse__still {
  opacity: 0.35;
}
