/* ==========================================================================
   Playtime page layout. The DOM is in phone order: this week, Two Week Activity, key numbers, Pile of
   Shame, analytics, more numbers, habits, neglected. Desktop places them in rows:
   1. this week, habits and neglected | analytics over the Pile of Shame   2. the stat strip
   3. Two Week Activity across the page.
   Both columns of row 1 end together: the analytics charts grow into any height the left column
   adds, and Neglected grows when the right column is the taller one.
   ========================================================================== */
.pt-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--layout-gutter);
  counter-reset: pid 1336;
}

.pt-grid > section {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
}

.pt-grid turbo-frame {
  display: flex;
  flex-direction: column;
}

.pt-grid turbo-frame > :last-child {
  flex: 1;
}

.pt-grid > section > :last-child {
  flex: 1;
}

@media (min-width: 1200px) {
  .pt-grid {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-template-rows: auto auto 1fr auto auto auto;
    grid-template-areas:
      "hero hero hero hero hero chart chart chart chart chart chart chart"
      "habits habits habits habits habits chart chart chart chart chart chart chart"
      "neglected neglected neglected neglected neglected chart chart chart chart chart chart chart"
      "neglected neglected neglected neglected neglected pile pile pile pile pile pile pile"
      "keys keys keys keys keys keys keys keys more more more more"
      "recent recent recent recent recent recent recent recent recent recent recent recent";
  }

  .pt-hero-area { grid-area: hero; }
  .pt-habits-area { grid-area: habits; }
  .pt-neglected-area { grid-area: neglected; }
  .pt-analytics-area { grid-area: chart; }
  .pt-keys-area { grid-area: keys; }
  .pt-more-area { grid-area: more; }
  .pt-recent-area { grid-area: recent; }
  .pt-pile-area { grid-area: pile; }

  /* The stat strip keeps the page gutter between its tiles too, so key and more numbers read as one row. */
  .pt-grid .pt-stats {
    gap: var(--layout-gutter);
  }

  /* Netrunner stacks the two stat lists into one process monitor. */
  :root[data-theme="hacker"] .pt-grid {
    grid-template-areas:
      "hero hero hero hero hero chart chart chart chart chart chart chart"
      "habits habits habits habits habits chart chart chart chart chart chart chart"
      "neglected neglected neglected neglected neglected chart chart chart chart chart chart chart"
      "neglected neglected neglected neglected neglected pile pile pile pile pile pile pile"
      "keys keys keys keys keys keys keys keys keys keys keys keys"
      "more more more more more more more more more more more more"
      "recent recent recent recent recent recent recent recent recent recent recent recent";
    grid-template-rows: auto auto 1fr auto auto auto auto;
  }

  :root[data-theme="hacker"] .pt-more-area {
    margin-top: calc(-1 * var(--layout-gutter));
  }
}

@media (max-width: 767px) {
  .pt-grid {
    gap: var(--space-4);
  }
}

/* A scope line: what a number covers ("Last 14 days", "Lifetime (Steam)"). */
.pt-scope {
  margin: 0;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  color: var(--text-secondary);
}

/* ==========================================================================
   This week (the hero)
   ========================================================================== */
.pt-hero {
  display: grid;
  gap: var(--space-4);
}

.pt-hero-head,
.pt-panel-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-1) var(--space-3);
}

.pt-hero-title,
.pt-panel-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 700;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-primary);
}

.pt-hero-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-6);
}

.pt-gauge {
  position: relative;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
}

.pt-gauge > * {
  grid-area: 1 / 1;
}

/* The ring only shows in Goshboard OS. */
.pt-gauge-ring {
  display: none;
}

.pt-hero-value {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--text-primary);
}

.pt-hero-facts {
  display: grid;
  flex: 1 1 14rem;
  gap: var(--space-2);
  min-inline-size: 0;
}

.pt-hero-facts p {
  margin: 0;
}

.pt-hero-delta {
  font-weight: 700;
  color: var(--text-secondary);
}

.pt-hero-delta[data-direction="up"] {
  color: var(--success);
}

.pt-hero-note {
  font-size: var(--text-xs);
  font-style: italic;
  color: var(--text-secondary);
}

.pt-hero-today {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
}

.pt-hero-today-label {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.pt-hero-today-value {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--text-primary);
}

.pt-hero-usual {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* The week day by day: a sparkline over seven columns, each day with its time. */
.pt-week {
  display: grid;
  gap: var(--space-2);
  margin: 0;
}

.pt-week-spark {
  display: block;
  inline-size: 100%;
  block-size: 2.5rem;
  overflow: visible;
}

.pt-spark-line {
  fill: none;
  stroke: var(--chart-1);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.pt-week-days {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: center;
}

.pt-week-day {
  display: grid;
  gap: 2px;
  min-inline-size: 0;
}

.pt-week-dayname {
  font-size: var(--text-xs);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.pt-week-dayname abbr {
  text-decoration: none;
}

.pt-week-daytime {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  overflow-wrap: anywhere;
}

/* The punched hole shows only on the Retro Desk timesheet. */
.pt-punch {
  display: none;
}

/* Goshboard OS signature: a HUD gauge rings the week's total, filled to this week's share of the
   usual week (the 4-week average), with a conic sweep confined to the ring's band, clear of the text. */
:root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-gauge {
  inline-size: 11rem;
  aspect-ratio: 1;
}

:root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-gauge::before {
  content: "";
  grid-area: 1 / 1;
  inline-size: 100%;
  block-size: 100%;
  border-radius: 50%;
  background: conic-gradient(from 0deg, rgb(var(--accent-rgb) / .35), rgb(var(--accent-rgb) / 0) 30%);
  mask: radial-gradient(closest-side, transparent 86%, #000 87%, #000 99%, transparent 100%);
}

:root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-gauge-ring {
  display: block;
  overflow: visible;
  inline-size: 100%;
  block-size: 100%;
  transform: rotate(-90deg);
}

.pt-gauge-track,
.pt-gauge-ticks,
.pt-gauge-fill {
  fill: none;
}

.pt-gauge-track {
  stroke: rgb(var(--accent-rgb) / .14);
  stroke-width: 6;
}

.pt-gauge-ticks {
  stroke: rgb(var(--accent-rgb) / .45);
  stroke-width: 3;
  stroke-dasharray: .4 4.6;
}

.pt-gauge-fill {
  stroke: var(--accent);
  stroke-width: 6;
  stroke-linecap: round;
  filter: drop-shadow(0 0 4px rgb(var(--accent-rgb) / .8));
}

:root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-hero-value {
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  max-inline-size: 7.5rem;
  text-align: center;
  text-shadow: var(--glow-text);
}

:root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-hero-part + .pt-hero-part {
  font-size: var(--text-lg);
  color: var(--text-secondary);
}

@media (prefers-reduced-motion: no-preference) {
  :root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-gauge::before {
    animation: pt-sweep 8s linear infinite;
  }
}

@keyframes pt-sweep {
  to { rotate: 1turn; }
}

/* Retro Desk signature: a ruled timesheet. A double margin rule, a typed total, and one ruled line per
   weekday with a hole punched for each day played. The rules sit under each line of text, never
   across it. Soft shadows only. */
:root[data-theme="beige"] .pt-hero {
  padding-left: calc(var(--space-6) + 6px);
  background: var(--surface-raised);
  border-left: 4px double var(--accent-deep);
}

:root[data-theme="beige"] .pt-hero-head {
  padding-bottom: var(--space-2);
  border-bottom: 2px solid var(--border-strong);
}

:root[data-theme="beige"] .pt-hero-title::before {
  content: "Time card: ";
}

:root[data-theme="beige"] .pt-hero-value {
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
}

:root[data-theme="beige"] .pt-week-spark {
  display: none;
}

:root[data-theme="beige"] .pt-week-days {
  grid-template-columns: minmax(0, 1fr);
  text-align: left;
}

:root[data-theme="beige"] .pt-week-day {
  grid-template-columns: 4rem 1.25rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
  padding-block: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
}

:root[data-theme="beige"] .pt-week-daytime {
  font-size: var(--text-sm);
}

:root[data-theme="beige"] .pt-punch {
  display: block;
  inline-size: 10px;
  block-size: 14px;
  border: 1px dashed var(--punch-ring);
  border-radius: 2px;
}

:root[data-theme="beige"] .pt-week-day.is-played .pt-punch {
  background: var(--punch-hole);
  border: 1px solid var(--punch-hole);
}

/* Netrunner: the week as an uptime readout. */
:root[data-theme="hacker"] .pt-hero-title::before {
  content: "$ uptime --week" / "";
  margin-right: var(--space-2);
  font-weight: 400;
  text-transform: none;
  color: var(--text-secondary);
}

:root[data-theme="hacker"] .pt-hero-value {
  text-shadow: var(--glow-text);
}

:root[data-theme="hacker"] .pt-spark-line {
  stroke-linejoin: miter;
  stroke-linecap: square;
}

/* ==========================================================================
   The stat strip: value, label, detail and scope per tile. No badges.
   ========================================================================== */
.pt-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
  margin: 0;
}

@media (min-width: 768px) {
  .pt-stats {
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
    grid-template-columns: none;
  }
}

.pt-stat {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-inline-size: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--surface-card);
  border: var(--border-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  counter-increment: pid;
}

.pt-stat dd {
  margin: 0;
  min-inline-size: 0;
}

.pt-stat-value {
  order: -1;
  overflow: hidden;
  font-family: var(--font-data);
  font-size: var(--text-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-tight);
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
}

.pt-stat-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-primary);
}

.pt-stat-detail {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.pt-stat-scope {
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

/* The %CPU column and its heads belong to the Netrunner monitor only. */
.pt-stat-cpu,
.pt-monitor-cols,
.pt-monitor-head {
  display: none;
}

/* A tile with a game is one link: it stretches over the tile, a chevron marks it, and the whole tile
   shows hover and focus. Long names end in an ellipsis; the title has them in full. */
.stat-link {
  display: block;
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stat-link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.stat-link:focus-visible {
  outline: none;
}

.pt-stat.has-link {
  cursor: pointer;
}

.pt-stat.has-link:hover,
.pt-stat.has-link:has(.stat-link:focus-visible) {
  border-color: var(--border-strong);
}

.pt-stat.has-link:has(.stat-link:focus-visible) {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.pt-stat.has-link:hover .stat-link,
.pt-stat.has-link:has(.stat-link:focus-visible) .stat-link {
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-underline-offset: 3px;
}

.pt-stat-cue {
  inline-size: .5em;
  block-size: .5em;
  margin-left: auto;
  border-top: 2px solid var(--accent);
  border-right: 2px solid var(--accent);
  rotate: 45deg;
}

/* Retro Desk: index cards, a ruled line under the value only. */
:root[data-theme="beige"] .pt-stat {
  background: var(--surface-raised);
  border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-pop);
}

:root[data-theme="beige"] .pt-stat-value {
  padding-bottom: 2px;
  border-bottom: 1px solid rgb(var(--accent-rgb) / .22);
}

/* Netrunner signature: the strip as `top`. One row per stat (PID, GAME, TIME, %CPU with an inline bar),
   its scope and detail on a second line, under an inverse column header and a Tasks line. */
:root[data-theme="hacker"] .pt-monitor-head {
  display: block;
  margin: 0 0 var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

:root[data-theme="hacker"] .pt-monitor-cols,
:root[data-theme="hacker"] .pt-stat {
  display: grid;
  grid-template-columns: 5ch minmax(0, 16ch) minmax(0, 1fr) 12ch;
  column-gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

:root[data-theme="hacker"] .pt-monitor-cols {
  margin: 0;
  padding: 2px var(--space-3);
  color: var(--on-accent);
  font-weight: 700;
  background: var(--accent);
}

:root[data-theme="hacker"] .pt-more-area .pt-monitor-cols {
  display: none;
}

:root[data-theme="hacker"] .pt-stats {
  display: block;
  background: var(--surface-page);
  border: 1px solid var(--border-strong);
  border-top: 0;
}

:root[data-theme="hacker"] .pt-more-area .pt-stats {
  border-top: 1px dashed var(--border-subtle);
}

:root[data-theme="hacker"] .pt-stat {
  grid-template-areas:
    "pid label value cpu"
    ". detail detail detail"
    ". scope scope scope";
  row-gap: 0;
  padding: var(--space-1) var(--space-3);
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

:root[data-theme="hacker"] .pt-stat::before {
  content: counter(pid);
  grid-area: pid;
  color: var(--text-secondary);
}

:root[data-theme="hacker"] .pt-stat-label {
  grid-area: label;
  overflow: hidden;
  font-family: inherit;
  font-size: inherit;
  font-weight: 400;
  letter-spacing: 0;
  text-overflow: ellipsis;
  white-space: nowrap;
}

:root[data-theme="hacker"] .pt-stat-value {
  grid-area: value;
  font-size: inherit;
  text-shadow: var(--glow-text);
}

:root[data-theme="hacker"] .pt-stat-detail {
  grid-area: detail;
  font-size: var(--text-xs);
}

:root[data-theme="hacker"] .pt-stat-scope {
  grid-area: scope;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-faint);
}

:root[data-theme="hacker"] .pt-stat-scope::before {
  content: "# " / "";
}

:root[data-theme="hacker"] .pt-stat-cpu {
  display: flex;
  grid-area: cpu;
  align-items: center;
  gap: var(--space-2);
}

:root[data-theme="hacker"] .pt-stat-cpu::before {
  content: attr(data-share);
  flex: 0 0 4ch;
  text-align: right;
}

:root[data-theme="hacker"] .pt-stat-bar {
  flex: 1;
  block-size: .6em;
  background: rgb(var(--accent-rgb) / .15);
}

.pt-stat-bar-fill {
  fill: var(--accent);
}

:root[data-theme="hacker"] .pt-stat-cue {
  border-color: var(--text-secondary);
}

:root[data-theme="hacker"] .pt-stat.has-link:hover {
  background: var(--surface-row-hover);
}

@media (max-width: 767px) {
  :root[data-theme="hacker"] .pt-monitor-cols,
  :root[data-theme="hacker"] .pt-stat {
    grid-template-columns: 4ch minmax(0, 1fr) minmax(0, 1fr) 5ch;
    column-gap: var(--space-2);
    font-size: var(--text-xs);
  }

  :root[data-theme="hacker"] .pt-stat-bar {
    display: none;
  }

  :root[data-theme="hacker"] .pt-stat-cpu::before {
    flex-basis: auto;
  }
}

/* ==========================================================================
   Panels: session habits and neglected games
   ========================================================================== */
.pt-panel {
  display: grid;
  align-content: start;
  gap: var(--space-4);
}

.pt-panel-empty {
  margin: 0;
  color: var(--text-secondary);
}

.pt-buckets {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.pt-buckets th,
.pt-buckets td {
  padding-block: var(--space-1);
}

.pt-bucket-label {
  inline-size: 7.5rem;
  font-weight: 400;
  text-align: left;
  white-space: nowrap;
  color: var(--text-secondary);
}

.pt-bucket-count {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

.pt-bucket-bar {
  flex: 1;
  block-size: .5rem;
  background: rgb(var(--accent-rgb) / .1);
  border-radius: var(--radius-xs);
}

.pt-bucket-fill {
  fill: var(--chart-1);
}

.pt-late-night {
  margin: 0;
  color: var(--text-secondary);
}

.pt-late-night-value {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--text-primary);
}

.pt-neglected-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.pt-neglected-item {
  display: grid;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  color: inherit;
  text-decoration: none;
  background: var(--surface-chip);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.pt-neglected-item:hover {
  background: var(--surface-chip-hover);
  border-color: var(--border-strong);
}

.pt-neglected-name {
  overflow: hidden;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
}

.pt-neglected-meta {
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

:root[data-theme="hacker"] .pt-neglected-name::before {
  content: "zombie " / "";
  color: var(--text-secondary);
}

/* ==========================================================================
   Two Week Activity: a labelled list that scrolls sideways
   ========================================================================== */
.recent-card::before {
  background: var(--gradient-secondary);
}

.recent-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  margin-bottom: var(--space-2);
}

/* The arrows sit beside the heading, off the art. Touch screens swipe instead. */
.recent-arrows {
  display: flex;
  gap: var(--space-2);
}

@media (pointer: coarse) {
  .recent-arrows {
    display: none;
  }
}

.scroll-arrow {
  display: grid;
  place-items: center;
  inline-size: 36px;
  block-size: 36px;
  color: var(--text-primary);
  background: var(--surface-chip);
  border: 1px solid var(--border-subtle);
  border-radius: 50%;
  cursor: pointer;
}

.scroll-arrow:hover:not(:disabled) {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--surface-chip-hover);
}

.scroll-arrow:disabled {
  opacity: .35;
  cursor: default;
}

/* Padding leaves room for each card's focus ring and lift; scroll-padding keeps a focused card clear
   of the faded edges. */
.recent-activity-container {
  display: flex;
  gap: var(--space-4);
  margin: 0;
  padding: var(--space-3) var(--space-2) var(--space-4);
  overflow-x: auto;
  list-style: none;
  scroll-padding-inline: 3rem;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
}

.recent-activity-container[data-more-end] {
  mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
}

.recent-activity-container[data-more-start] {
  mask-image: linear-gradient(to right, transparent, #000 2rem);
}

.recent-activity-container[data-more-start][data-more-end] {
  mask-image: linear-gradient(to right, transparent, #000 2rem, #000 calc(100% - 2rem), transparent);
}

/* While a card has focus, no edge fades over it. */
.recent-activity-container:focus-within {
  mask-image: none;
}

.capsule-item {
  flex: 0 0 auto;
  scroll-snap-align: start;
}

.capsule-card {
  position: relative;
  display: block;
  inline-size: 200px;
  aspect-ratio: 2 / 3;
  overflow: hidden;
  color: var(--on-art);
  text-decoration: none;
  background: var(--surface-sunken);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 20px rgb(0 0 0 / .45);
  transition: transform .3s cubic-bezier(.16, 1, .3, 1), box-shadow .3s ease, border-color .3s ease;
}

.capsule-card:hover,
.capsule-card:focus-visible {
  transform: translateY(-4px);
  border-color: var(--border-strong);
  box-shadow: 0 14px 28px rgb(0 0 0 / .55), 0 0 16px rgb(var(--accent-rgb) / .25);
}

.capsule-image {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.16, 1, .3, 1);
}

.capsule-card:hover .capsule-image {
  transform: scale(1.04);
}

/* The name and time sit on a near-opaque scrim, never on bare art: AA over any cover. The sparkline
   lives in the scrim's fade, where no text is. */
.capsule-overlay {
  position: absolute;
  inset: auto 0 0;
  display: grid;
  gap: var(--space-1);
  padding: 2.25rem var(--space-3) var(--space-3);
  background: linear-gradient(to top, rgb(0 0 0 / .9) calc(100% - 2.25rem), rgb(0 0 0 / 0));
}

.capsule-spark {
  position: absolute;
  inset: .5rem var(--space-3) auto;
  inline-size: calc(100% - 2 * var(--space-3));
  block-size: 1.25rem;
  overflow: visible;
}

.capsule-title {
  display: -webkit-box;
  overflow: hidden;
  font-weight: 700;
  line-height: 1.25;
  color: var(--on-art);
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
}

.capsule-stats {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--space-2);
}

.game-hours-large {
  font-family: var(--font-data);
  font-size: var(--text-xl);
  font-weight: 800;
  color: var(--on-art);
}

.capsule-note {
  font-size: var(--text-xs);
  color: var(--on-art-muted);
}

@media (max-width: 767px) {
  .capsule-card {
    inline-size: 150px;
  }

  .game-hours-large {
    font-size: var(--text-lg);
  }
}

/* Retro Desk: file folders with a tab, the name on a paper label instead of a scrim. */
:root[data-theme="beige"] .capsule-item {
  padding-top: 12px;
}

:root[data-theme="beige"] .capsule-card {
  overflow: visible;
  color: var(--text-primary);
  background: var(--surface-raised);
  border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-pop);
}

:root[data-theme="beige"] .capsule-card::before {
  content: "";
  position: absolute;
  top: -12px;
  left: 15px;
  inline-size: 60px;
  block-size: 12px;
  background: var(--surface-raised);
  border: 1px solid var(--border-subtle);
  border-bottom: 0;
}

:root[data-theme="beige"] .capsule-overlay {
  padding-top: var(--space-2);
  background: var(--surface-raised);
  border-top: 1px solid var(--border-strong);
}

:root[data-theme="beige"] .capsule-spark {
  position: static;
  inline-size: 100%;
  block-size: 1rem;
}

:root[data-theme="beige"] .capsule-title {
  color: var(--text-primary);
}

:root[data-theme="beige"] .game-hours-large {
  color: var(--accent);
}

:root[data-theme="beige"] .capsule-note {
  color: var(--text-secondary);
}

/* Netrunner: a black readout under the art. */
:root[data-theme="hacker"] .capsule-card {
  border-radius: 0;
}

:root[data-theme="hacker"] .capsule-overlay {
  padding-top: 2rem;
  background: linear-gradient(to top, #000 calc(100% - 2rem), rgb(0 0 0 / 0));
}

:root[data-theme="hacker"] .capsule-title {
  color: var(--text-primary);
}

:root[data-theme="hacker"] .game-hours-large {
  color: var(--accent);
  text-shadow: var(--glow-text);
}

:root[data-theme="hacker"] .capsule-note {
  color: var(--text-secondary);
}

/* ==========================================================================
   Playtime Analytics: three stacked charts, each with a table
   ========================================================================== */
.charts-container-card::before {
  background: var(--gradient-primary);
}

/* When the card is taller than its charts (it ends with the left column), the trend and the chart pair
   share the extra height and each chart grows into it; a year view sits centred in its panel. */
.charts-container-card {
  display: flex;
  flex-direction: column;
}

.charts-container-card > .chart-block,
.chart-pair {
  flex: 1 0 auto;
}

.chart-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-inline-size: 0;
}

/* A chart panel of the analytics card: grows with its block. */
.chart-fill {
  display: flex;
  flex-direction: column;
  justify-content: center;
  flex: 1 0 auto;
}

/* The chart takes the height it is given and adds none of its own, so it can shrink again. */
.charts-container-card .chart-canvas-container {
  contain: size;
}

.chart-block-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.chart-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 700;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-primary);
}

.chart-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  margin-top: var(--space-6);
}

@media (min-width: 768px) {
  .chart-pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.chart-canvas-container {
  flex: 1;
  min-height: 180px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.chart-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 1rem;
  min-height: 28px;
}

.chart-caption {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-family: var(--font-body);
  margin: 0;
}

.chart-filters {
  display: flex;
  gap: 0.5rem;
}

.chart-time-btn {
  background: var(--surface-chip);
  border: 1px solid rgb(var(--accent-rgb) / .2);
  color: var(--text-secondary);
  padding: 0.3rem 0.8rem;
  border-radius: 12px;
  font-size: 0.75rem;
  font-family: var(--font-display);
  letter-spacing: 1px;
  text-transform: uppercase;
  text-decoration: none;
  transition: all 0.2s ease;
}

.chart-time-btn:hover {
  background: rgb(var(--accent-rgb) / .1);
  color: var(--text-primary);
  border-color: rgb(var(--accent-rgb) / .5);
}

/* Not by colour alone: the current range is also bold and underlined. */
.chart-time-btn.active {
  background: rgb(var(--accent-rgb) / .2);
  color: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 10px rgb(var(--accent-rgb) / .2);
  font-weight: 700;
  text-decoration: underline 2px;
  text-underline-offset: 3px;
}

:root[data-theme="beige"] .chart-time-btn.active {
  box-shadow: none;
}

.chart-table summary {
  inline-size: fit-content;
  font-size: var(--text-sm);
  color: var(--accent);
  cursor: pointer;
}

.chart-table-scroll {
  max-block-size: 16rem;
  margin-top: var(--space-2);
  overflow: auto;
}

.chart-table table {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.chart-table th,
.chart-table td {
  padding: var(--space-1) var(--space-2);
  text-align: left;
  border-bottom: 1px solid var(--border-subtle);
}

.chart-table td {
  text-align: right;
}

.chart-table thead th {
  position: sticky;
  top: 0;
  color: var(--text-secondary);
  background: var(--surface-raised);
}

.chart-table tbody th {
  font-weight: 400;
  color: var(--text-primary);
}

.btn-ignore-toggle {
  background: var(--surface-chip);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  border-radius: 8px;
  padding: 0.45rem 0.8rem;
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1px;
  cursor: pointer;
  transition: all 0.3s ease;
  line-height: 1;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.btn-ignore-toggle:hover {
  background: rgb(var(--danger-rgb) / .2);
  border-color: rgb(var(--danger-rgb) / .5);
  color: var(--text-primary);
  transform: translateY(-2px);
  box-shadow: 0 6px 15px rgb(var(--danger-rgb) / .2);
}

.btn-ignore-toggle.active {
  background: rgb(var(--accent-rgb) / .1);
  border-color: rgb(var(--accent-rgb) / .3);
  color: var(--accent);
}

.btn-ignore-toggle.active:hover {
  background: rgb(var(--accent-rgb) / .2);
  border-color: rgb(var(--accent-rgb) / .5);
  color: var(--text-primary);
  transform: translateY(-2px);
  box-shadow: 0 6px 15px rgb(var(--accent-rgb) / .2);
}

/* Logged-out landing */
.landing {
  max-width: 900px;
  margin: 0 auto;
  padding: var(--space-8) 0;
  text-align: center;
}

.landing-title {
  margin-bottom: var(--space-4);
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: 700;
  line-height: var(--leading-tight);
  color: var(--text-primary);
}

.landing-lead {
  max-width: 40rem;
  margin: 0 auto var(--space-8);
  font-size: var(--text-lg);
  color: var(--text-secondary);
}

.landing-note {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.landing-features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--layout-gutter);
  margin: var(--space-12) 0;
  text-align: left;
}

.landing-feature-title {
  margin-bottom: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-md);
  letter-spacing: var(--tracking-label);
  color: var(--accent);
}

/* As wide as the feature cards above it, so both blocks share their edges. */
.landing-before {
  margin: 0 auto;
  padding: var(--space-6);
  text-align: left;
  background: var(--surface-chip);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.landing-before h2 {
  margin-bottom: var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-md);
}

.landing-before ol {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-left: var(--space-6);
}

.landing-before a {
  color: var(--accent);
}

/* ==========================================================================
   Game dialog content (playtime_dashboard/game)
   ========================================================================== */
.game-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  align-content: start;
}

.game-dialog-media {
  margin: calc(-1 * var(--modal-pad)) calc(-1 * var(--modal-pad)) 0;
  block-size: clamp(7rem, 24vw, 12rem);
  overflow: hidden;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--border-subtle);
}

.game-dialog-hero {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: center 25%;
}

.game-dialog-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.game-dialog-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: var(--space-3);
  margin: 0;
}

.game-dialog-stat {
  padding: var(--space-3) var(--space-4);
  background: var(--surface-chip);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.game-dialog-stat dt {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.game-dialog-stat dd {
  margin: var(--space-1) 0 0;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--text-primary);
}

.game-dialog-unit {
  margin-left: var(--space-1);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 400;
  color: var(--text-secondary);
}

.game-dialog-panel {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--surface-inset);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.game-dialog-heading {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-md);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-primary);
}

.game-dialog-empty {
  color: var(--text-secondary);
}

.game-ignore-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
}

.game-ignore-text {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* Achievements */
.achievement-summary {
  color: var(--text-secondary);
}

.achievement-summary strong {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  color: var(--accent);
}

.achievement-bar {
  inline-size: 100%;
  block-size: .5rem;
  appearance: none;
  background: var(--surface-chip-hover);
  border: 0;
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.achievement-bar::-webkit-progress-bar {
  background: var(--surface-chip-hover);
}

.achievement-bar::-webkit-progress-value {
  background: var(--accent);
}

.achievement-bar::-moz-progress-bar {
  background: var(--accent);
}

.achievement-group {
  display: grid;
  gap: var(--space-2);
}

.achievement-label {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-faint);
}

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

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

.achievement-icon {
  flex-shrink: 0;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}

.achievement-text {
  display: grid;
  flex: 1;
  min-inline-size: 0;
}

.achievement-name {
  font-weight: 700;
  color: var(--text-primary);
}

.achievement-desc,
.achievement-meta {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.achievement-meta {
  flex-shrink: 0;
  text-align: right;
}

.achievement-row.is-locked .achievement-name {
  color: var(--text-secondary);
}

/* Sessions */
.session-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.session-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--surface-chip);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}

.session-when {
  display: grid;
}

.session-date {
  font-weight: 600;
  color: var(--text-primary);
}

.session-time {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.session-length {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--accent);
}

/* An estimated session is real time, but its hour is a guess: quieter than a timed one. */
.session-row.is-estimated {
  background: transparent;
  border-style: dashed;
}

.session-row.is-estimated .session-date,
.session-row.is-estimated .session-length {
  font-weight: 400;
  color: var(--text-secondary);
}

.session-row.is-estimated .session-time {
  font-size: var(--text-xs);
  font-style: italic;
  color: var(--text-faint);
}

.session-more summary {
  margin-block: var(--space-3);
  color: var(--accent);
  cursor: pointer;
}

/* ==========================================================================
   Year view: the "1 Year" range of a playtime chart
   ========================================================================== */
.year-view {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
}

.year-note {
  padding: var(--space-3) var(--space-4);
  color: var(--text-secondary);
  background: var(--surface-chip);
  border: 1px dashed var(--border-subtle);
  border-radius: var(--radius-md);
}

.year-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-3);
  margin: 0;
}

.year-stat {
  padding: var(--space-3);
  background: var(--surface-chip);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.year-stat dt {
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.year-stat dd {
  display: grid;
  margin: var(--space-1) 0 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--text-primary);
}

.year-stat-detail {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 400;
  color: var(--text-secondary);
  overflow-wrap: anywhere;
}

.year-figure {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  min-inline-size: 0;
}

.year-caption {
  margin: 0;
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-secondary);
}

/* Heatmap: one column per week, Monday on top. It scrolls sideways on a narrow screen. */
.year-heatmap-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  padding-bottom: var(--space-2);
}

.year-heatmap {
  display: flex;
  gap: var(--space-1);
  min-inline-size: 30rem;
}

.year-weekdays,
.year-grid {
  display: grid;
  grid-template-rows: 1rem repeat(7, auto);
  gap: 2px;
}

.year-weekdays {
  font-size: var(--text-xs);
  line-height: 1;
  color: var(--text-faint);
}

.year-weekdays span {
  display: flex;
  align-items: center;
}

.year-grid {
  flex: 1;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
}

.year-month-label {
  font-size: var(--text-xs);
  line-height: 1;
  white-space: nowrap;
  color: var(--text-secondary);
}

.year-cell {
  display: block;
  aspect-ratio: 1;
  min-inline-size: .4rem;
  background: var(--heat-0);
  border-radius: var(--radius-xs);
  box-shadow: inset 0 0 0 1px var(--heat-outline);
}

.year-cell.level-1 { background: var(--heat-1); }
.year-cell.level-2 { background: var(--heat-2); }
.year-cell.level-3 { background: var(--heat-3); }
.year-cell.level-4 { background: var(--heat-4); }

/* Before tracking started: hatched, so it never reads as a day without play. */
.year-cell.is-untracked {
  background: repeating-linear-gradient(135deg, transparent 0 2px, var(--heat-outline) 2px 4px);
}

.year-cell.is-outside {
  visibility: hidden;
}

.year-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

.year-legend .year-cell {
  inline-size: .75rem;
  min-inline-size: 0;
}

.year-legend-gap {
  inline-size: var(--space-4);
}

/* Monthly bars: an SVG stretched to the width, labels underneath. */
.year-bars {
  display: block;
  inline-size: 100%;
  block-size: 9rem;
  border-bottom: 1px solid var(--chart-grid);
}

.year-bar {
  fill: var(--chart-1);
  opacity: .75;
}

.year-bar.is-best {
  opacity: 1;
}

.year-bar.is-untracked {
  fill: none;
  stroke: var(--border-subtle);
  stroke-dasharray: 4 3;
  vector-effect: non-scaling-stroke;
  opacity: 1;
}

.year-bar-labels {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-xs);
  text-align: center;
  color: var(--text-secondary);
}

.year-top-games {
  display: grid;
  gap: var(--space-3);
}

.year-top-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.year-top-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--surface-chip);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}

.year-top-month {
  font-size: var(--text-xs);
  text-transform: uppercase;
  color: var(--text-faint);
}

.year-top-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
}

.year-top-name:hover,
.year-top-name:focus-visible {
  color: var(--accent);
}

.year-top-time {
  font-size: var(--text-sm);
  color: var(--accent);
}

@media (max-width: 40rem) {
  .game-dialog-media {
    margin-inline: calc(-1 * var(--space-4));
  }
}

.game-ignore-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.ignore-toggle-form {
  display: inline-flex;
  margin: 0;
  padding: 0;
}

/* Reduced motion: no lift or zoom on the cards, no sweep on the gauge. The tokens stylesheet already cuts every
   animation and transition short; this removes the movement itself. The page has no slide fades left,
   and its cards no longer fade in, so a refresh broadcast no longer replays an entrance. */
@media (prefers-reduced-motion: reduce) {
  .capsule-card,
  .capsule-image {
    transition: none;
  }

  .capsule-card:hover,
  .capsule-card:focus-visible,
  .capsule-card:hover .capsule-image {
    transform: none;
  }

  .recent-activity-container {
    scroll-snap-type: none;
  }
}

/* Phones: the card headings shrink, and the gauge sits beside the week's facts. */
@media (max-width: 767px) {
  .pt-grid .card-header {
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-4);
  }

  .pt-grid .card-header h2 {
    font-size: var(--text-lg);
    letter-spacing: 2px;
  }

  :root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-gauge {
    inline-size: 8.5rem;
  }

  :root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-hero-value {
    font-size: var(--text-2xl);
  }

  :root:not([data-theme="beige"]):not([data-theme="hacker"]) .pt-hero-facts {
    flex-basis: 9rem;
  }
}
