/* ============================================================
   Screens — tiles, rows, doors, the weekend calendar, the map,
   the operations rail, the detail sheet and the timeline

   Nothing here invents a container. A tile is a panel; inside a
   tile it is flat rows with hairline separation, never a card.
   ============================================================ */

/* ============================================================
   Tiles

   A layout primitive, used where a page genuinely has several
   parallel objects. Every tile is a job with a verb: no tile is
   a number for its own sake, and any count on a tile is a count
   of something you can act on from that tile.
   ============================================================ */
.bento {
  display: grid;
  grid-template-columns: 1fr;
  column-gap: var(--s4);
  row-gap: var(--s5);
}

.tile {
  min-width: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  container-type: inline-size;
}

.tile-head {
  padding: 13px var(--s4);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
  min-height: 52px;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--line-soft);
}

.tile-name {
  font-size: var(--t-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-tight);
  min-width: 0;
}

.tile-note {
  font-size: var(--t-sm);
  font-weight: var(--fw-medium);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tile-body { flex: 1; min-width: 0; }
.tile-pad { padding: var(--s4); }

/* Tone reaches the note and nothing else. An earlier pass washed
   the whole header in the status colour, which made a tile with
   one item still to set up shout as loudly as a real problem;
   the words already say which it is. Colour marks the sentence
   that carries the state, not the furniture around it. */
.tile[data-tone] .tile-note { font-weight: var(--fw-semibold); }
.tile[data-tone="wait"] .tile-note { color: var(--attention-ink); }
.tile[data-tone="ok"] .tile-note { color: var(--positive-ink); }

/* ============================================================
   Rows — flat, hairline separated, one per thing
   ============================================================ */
.rows { display: flex; flex-direction: column; }

.rows-card {
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.row {
  padding: var(--s4);
  border-bottom: 1px solid var(--line-soft);
  animation: rise-in 340ms var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}

.rows > .row:last-child,
.rows-card > .row:last-child { border-bottom: 0; }

/* The day is the label and the hours are the answer, so they
   stack: day quiet and small above, hours loud and tabular
   below. Side by side they wrapped mid-range into "10:00 to /
   12:00", which reads as two times. */
.row-when {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--t-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-over);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.row-when b {
  font-size: var(--t-md);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-tight);
  text-transform: none;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.row-addr {
  margin-top: 4px;
  font-size: var(--t-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-tight);
  color: var(--ink);
}

.row-meta { margin-top: 2px; font-size: var(--t-sm); color: var(--ink-muted); }
.row-meta.is-flag { color: var(--attention-ink); font-weight: var(--fw-medium); }

.row-state { font-size: var(--t-sm); font-weight: var(--fw-semibold); line-height: 1.4; }
.row-state.ok { color: var(--positive-ink); }
.row-state.pending { color: var(--attention-ink); }
.row-state.stop { color: var(--danger-ink); }

.row-act { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }

/* ---- The wide row: my weekend ---- */
.row-wide { display: grid; gap: var(--s2); }

/* ---- The offer row: an open house somebody could take ---- */
.row-offer { display: grid; gap: var(--s3); }

.row-open {
  width: 100%;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  border-radius: var(--r-sm);
}

.row-offer.is-blocked { background: var(--surface-sunken); }
.row-offer.is-blocked .row-addr,
.row-offer.is-blocked .row-when b { color: var(--ink-soft); }

@media (hover: hover) and (pointer: fine) {
  .row-open:hover .row-addr { text-decoration: underline; text-underline-offset: 3px; }
}

/* ============================================================
   The thing you owe

   One obligation, stated as a question, opening in place. Never
   a modal: an inline panel can do this.
   ============================================================ */
.ask {
  border: 1px solid var(--attention-line);
  border-radius: var(--r-xl);
  background: var(--attention-soft);
  overflow: hidden;
}

.ask-row {
  width: 100%;
  min-height: 58px;
  padding: var(--s3) var(--s4);
  display: flex;
  align-items: center;
  gap: var(--s3);
  text-align: left;
}

.ask-q { flex: 1; min-width: 0; font-size: var(--t-md); font-weight: var(--fw-semibold); line-height: 1.35; }

.ask-go {
  flex: none;
  font-size: var(--t-sm);
  font-weight: var(--fw-semibold);
  color: var(--attention-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.ask-body { padding: 0 var(--s4) var(--s4); }

/* ============================================================
   Doors to the other pages

   A count and a link. Never a copy of what is behind them.
   ============================================================ */
.jumps { display: grid; gap: var(--s3); }

.jump {
  min-height: 76px;
  padding: var(--s4);
  display: flex;
  align-items: center;
  gap: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  animation: rise-in 340ms var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 60ms);
  transition:
    background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}

.jump:active { transform: scale(0.99); }

.jump-n {
  width: 42px;
  height: 42px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: var(--t-lg);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}

.jump[data-tone="wait"] .jump-n {
  background: var(--attention-soft);
  border-color: var(--attention-line);
  color: var(--attention-ink);
}

.jump[data-tone="ok"] .jump-n {
  background: var(--positive-soft);
  border-color: var(--positive-line);
  color: var(--positive-ink);
}

.jump-copy { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.jump-copy b { font-size: var(--t-md); font-weight: var(--fw-semibold); letter-spacing: var(--track-tight); }
.jump-copy i { font-style: normal; font-size: var(--t-sm); color: var(--ink-muted); }
/* A chevron is decoration, but it is still a glyph the audit
   rasterises and measures, so it meets the same 4.5:1 floor as
   any other mark on the page. */
.jump-go { flex: none; font-size: 1.4rem; line-height: 1; color: var(--ink-muted); }

@media (hover: hover) and (pointer: fine) {
  .jump:hover { background: var(--surface-hover); border-color: var(--line-strong); }
}

/* ============================================================
   Three views of one set
   ============================================================ */
.viewbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
}

.viewbar-n { font-size: var(--t-sm); color: var(--ink-muted); font-variant-numeric: tabular-nums; }

/* ============================================================
   The weekend as a calendar

   An hour rail down the side, a column per day, every open house
   sitting where it actually happens with the address and the host
   written on the block. No legend, because nothing is encoded.
   State is carried by fill and border together, so it survives
   with no colour perception.
   ============================================================ */
.cal {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s5);
  padding: var(--s4);
}

.cal-day { min-width: 0; }

.cal-day-head {
  height: 34px;
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  flex-wrap: wrap;
}

.cal-day-name { font-size: var(--t-base); font-weight: var(--fw-bold); letter-spacing: var(--track-tight); }

.cal-day-say {
  margin-left: auto;
  font-size: var(--t-sm);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.cal-day-say.is-short { color: var(--attention-ink); font-weight: var(--fw-semibold); }

.cal-body { display: grid; grid-template-columns: 40px minmax(0, 1fr); gap: 10px; }

.cal-rail { position: relative; min-height: 264px; }

.cal-hour {
  position: absolute;
  inset-inline-end: 0;
  font-size: var(--t-xs);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  transform: translateY(-50%);
  white-space: nowrap;
}

.cal-col {
  position: relative;
  container-type: inline-size;
  min-height: 264px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  overflow: hidden;
}

.cal-line { position: absolute; inset-inline: 0; height: 1px; background: var(--line); }

.cal-ev { position: absolute; padding: 1px; min-height: 26px; }

.cal-ev-in {
  height: 100%;
  padding: 4px 7px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  overflow: hidden;
  border: 1px solid;
  border-radius: var(--r-sm);
  transition: transform var(--t-fast) var(--ease-out);
}

.cal-ev b,
.cal-ev i {
  display: block;
  overflow: hidden;
  font-size: var(--t-xs);
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cal-ev b { font-weight: var(--fw-semibold); }
.cal-ev i { font-style: normal; }

.cal-ev[data-k="confirmed"] .cal-ev-in {
  border-color: var(--positive-line);
  background: var(--positive-soft);
  color: var(--positive-ink);
}

.cal-ev[data-k="waiting"] .cal-ev-in {
  border-color: var(--attention-line);
  background: var(--attention-soft);
  color: var(--attention-ink);
}

.cal-ev[data-k="problem"] .cal-ev-in {
  border-style: dotted;
  border-color: var(--danger-line);
  background: var(--danger-soft);
  color: var(--danger-ink);
}

/* Nobody yet: an outline, so an empty slot reads as a gap you
   could step into rather than an event that already exists. */
.cal-ev[data-k="open"] .cal-ev-in {
  border: 1.5px dashed var(--ink-faint);
  background: var(--surface-raised);
  color: var(--ink);
}

/* An agent's own open house is ringed, never recoloured. */
.cal-ev[data-mine="true"] .cal-ev-in { box-shadow: inset 0 0 0 1px currentColor; }
.cal-ev[data-mine="true"] i { font-weight: var(--fw-semibold); }

/* Hours already covered are the shape of the day, not something
   to press. They recede by fill rather than by opacity: half
   transparent text is unreadable outdoors, and a faded block is
   also the thing that hides content when the animation clock
   never advances. */
.cal-ev[data-ghost="true"] .cal-ev-in {
  border-style: solid;
  border-color: transparent;
  background: var(--surface);
  color: var(--ink-muted);
}

button.cal-ev {
  padding: 1px;
  border: 0;
  background: transparent;
  text-align: left;
  animation: ev-in 340ms var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 40ms);
}

@keyframes ev-in { from { transform: scale(0.955); } }

button.cal-ev:active .cal-ev-in { transform: scale(0.97); }
button.cal-ev:focus-visible { outline: none; }
button.cal-ev:focus-visible .cal-ev-in { box-shadow: 0 0 0 3px var(--accent-soft), 0 0 0 4px var(--focus); }

/* When a day is narrow enough that blocks are only a few
   characters wide, the status line goes and the address gets the
   room. Nothing is lost: a dashed outline already means "needs a
   host" and the day header carries the count. */
@container (max-width: 360px) {
  .cal-ev i { display: none; }
  .cal-ev b {
    font-size: 11px;
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
  }
  .cal-ev-in { padding: 3px 5px; justify-content: flex-start; }
}

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

@media (min-width: 1060px) {
  .cal { padding: var(--s4) var(--s5) var(--s5); gap: var(--s6); }
  .cal-col, .cal-rail { min-height: 300px; }
}

/* ============================================================
   Map

   Real coordinates, projected. DOM and not canvas, because a pin
   has to be reachable by keyboard and readable by a screen
   reader.
   ============================================================ */
.map {
  position: relative;
  aspect-ratio: 16 / 11;
  min-height: 280px;
  max-height: 460px;
  margin-inline: auto;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: radial-gradient(120% 90% at 30% 10%, var(--surface-raised) 0%, var(--surface-sunken) 70%);
}

.map-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 14.2857% 12.5%;
  opacity: 0.6;
}

.map-town {
  position: absolute;
  font-size: var(--t-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-over);
  text-transform: uppercase;
  color: var(--ink-muted);
  transform: translate(-50%, -50%);
  pointer-events: none;
  white-space: nowrap;
}

.map-pin {
  position: absolute;
  width: 46px;
  height: 46px;
  margin: -23px 0 0 -23px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
}

.map-dot {
  position: relative;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow:
    0 0 0 3px var(--surface-raised),
    0 2px 8px -1px oklch(24% 0.02 262 / 0.4);
  transition: transform var(--t-mid) var(--ease-out);
}

.map-pin[data-mine="true"] .map-dot { background: var(--positive-strong); }
.map-pin[data-clash="true"] .map-dot { background: var(--ink-faint); }

.map[data-fresh="true"] .map-pin {
  animation: pin-drop 520ms var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}

@keyframes pin-drop { from { transform: translateY(-15px) scale(0.72); } }

/* An unclaimed pin keeps a slow pulse: the one perpetual motion
   in the product, and it exists because "this still needs
   somebody" is the single thing the page is for. */
.map-pin:not([data-clash="true"]) .map-dot::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  opacity: 0;
  animation: pin-ping 2.6s var(--ease-out) infinite;
}

@keyframes pin-ping {
  0%   { opacity: 0.5; transform: scale(0.7); }
  70%  { opacity: 0; transform: scale(1.25); }
  100% { opacity: 0; transform: scale(1.25); }
}

.map-tip {
  position: absolute;
  inset-block-end: 100%;
  inset-inline-start: 50%;
  margin-bottom: 4px;
  padding: 5px 9px;
  border-radius: var(--r-md);
  background: var(--shell);
  color: var(--shell-ink);
  font-size: var(--t-xs);
  font-weight: var(--fw-semibold);
  line-height: 1.3;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 4px);
  transition:
    opacity var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}

.map-tip i { display: block; font-style: normal; font-weight: var(--fw-medium); color: var(--shell-ink-soft); }

.map-pin:focus-visible { outline: none; }

.map-pin:focus-visible .map-dot {
  transform: scale(1.25);
  box-shadow: 0 0 0 3px var(--surface-raised), 0 0 0 7px var(--focus);
}

.map-pin:focus-visible .map-tip,
.map-pin:active .map-tip { opacity: 1; transform: translate(-50%, 0); }

.map-note { margin-top: var(--s3); font-size: var(--t-sm); color: var(--ink-muted); }

/* ============================================================
   Operations rail

   A command rail, not a tile grid, because it is a work queue and
   not a home screen. Every number here is a filter or a
   destination, never a trophy.
   ============================================================ */
.rail {
  display: flex;
  flex-direction: column;
  padding: var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
}

.rail-line {
  max-width: 62ch;
  font-size: var(--t-lg);
  font-weight: var(--fw-medium);
  letter-spacing: var(--track-tight);
  line-height: 1.4;
  color: var(--ink);
}

.rail-line b { font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }

.rail-filters { display: flex; gap: var(--s2); flex-wrap: wrap; margin-top: var(--s4); }

/* The calendar runs full width below the summary so it has the
   same room to breathe as it does on the agent home. Squeezed
   into a side column it truncated every address to one letter. */
.rail-cov {
  margin-top: var(--s5);
  padding-top: var(--s2);
  border-top: 1px solid var(--line);
}

.rail-cov .cal { padding: var(--s4) 0 0; }

/* On a phone the map comes first and the filters drop to the
   bottom, next to the queue they actually control. */
@media (max-width: 640px) {
  .rail { padding: var(--s4); }
  .rail-line { font-size: var(--t-md); }
}

/* ---- A flag on a work card ---- */
.flag {
  margin-top: var(--s3);
  padding: var(--s3);
  border: 1px solid var(--danger-line);
  border-radius: var(--r-md);
  background: var(--danger-soft);
  color: var(--danger-ink);
  font-size: var(--t-sm);
  font-weight: var(--fw-medium);
  line-height: 1.45;
}

.card-actions { margin-top: var(--s4); gap: var(--s2); }

/* ---- Work cards get panel padding ---- */
#work .panel { padding: var(--s4); }

/* ============================================================
   Feedback inbox
   ============================================================ */
.fb {
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.fb + .fb { margin-top: var(--s3); }

.fb-head {
  padding: var(--s3) var(--s4);
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--line-soft);
}

.fb-head .p { font-size: var(--t-md); font-weight: var(--fw-semibold); letter-spacing: var(--track-tight); }
.fb-head .q { font-size: var(--t-sm); color: var(--ink-muted); }

.fb-item { padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line-soft); }
.fb-item:last-child { border-bottom: 0; }

.fb-item .who {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  flex-wrap: wrap;
  font-size: var(--t-sm);
}

.fb-item .who b { font-weight: var(--fw-semibold); color: var(--ink); }
.fb-item .who span { color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.fb-item .txt { margin-top: 4px; font-size: var(--t-base); color: var(--ink-soft); line-height: 1.5; }

/* ============================================================
   My listings — who is in it, and the hours you allow
   ============================================================ */
.host-list {
  display: grid;
  gap: 1px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--line);
}

.host-row {
  padding: 10px var(--s3);
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
  background: var(--surface-raised);
  font-size: var(--t-sm);
}

.host-row.is-flag { background: var(--attention-soft); }
.host-when { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; white-space: nowrap; }
.host-who { margin-left: auto; color: var(--ink-muted); }
.host-row.is-flag .host-who { color: var(--attention-ink); font-weight: var(--fw-medium); }

.win-row {
  padding: 10px 0;
  display: flex;
  align-items: center;
  gap: var(--s3);
  border-bottom: 1px solid var(--line-soft);
}

.win-row:last-of-type { border-bottom: 0; }
.win-day { min-width: 74px; font-size: var(--t-sm); font-weight: var(--fw-semibold); }
.win-val { margin-inline-end: auto; font-size: var(--t-sm); font-variant-numeric: tabular-nums; color: var(--ink-soft); }
.win-val.is-off { color: var(--ink-muted); }

.editor-note {
  max-width: 58ch;
  margin: var(--s3) 0;
  font-size: var(--t-sm);
  color: var(--ink-muted);
  line-height: 1.45;
}

/* ============================================================
   The detail sheet

   A native <dialog> so focus trapping, Escape and the top layer
   are the platform's job. A bottom sheet on a phone because that
   is where the thumb is; centred on a desk.
   ============================================================ */
.sheet {
  width: min(100%, 620px);
  max-height: 92dvh;
  margin: auto auto 0;
  inset-block-end: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
}

.sheet::backdrop { background: oklch(18% 0.02 262 / 0.45); }

/* It arrives from the bottom and leaves the same way, because a
   thing that comes in one way and goes out another reads as two
   different things. */
.sheet,
.sheet::backdrop {
  opacity: 0;
  transition:
    opacity var(--t-slow) var(--ease-out),
    transform var(--t-slow) var(--ease-out),
    overlay var(--t-slow) allow-discrete,
    display var(--t-slow) allow-discrete;
}

.sheet { transform: translateY(16px) scale(0.99); }
.sheet[open] { opacity: 1; transform: none; }
.sheet[open]::backdrop { opacity: 1; }

@starting-style {
  .sheet[open] { opacity: 0; transform: translateY(16px) scale(0.99); }
  .sheet[open]::backdrop { opacity: 0; }
}

.sheet-in {
  max-height: 92dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  background: var(--canvas);
  box-shadow: var(--shadow-rail);
}

.sheet-head { padding: var(--s5) var(--s4) var(--s4); border-bottom: 1px solid var(--line); background: var(--surface-raised); }
.sheet-title { font-size: var(--t-lg); font-weight: var(--fw-bold); letter-spacing: var(--track-tight); line-height: 1.25; }
.sheet-sub { margin-top: 3px; font-size: var(--t-sm); color: var(--ink-muted); }
.sheet-body { padding: var(--s5) var(--s4); overflow-y: auto; }

.sheet-foot {
  padding: var(--s4);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s2);
  border-top: 1px solid var(--line);
  background: var(--surface-raised);
}

.sheet-foot .btn { width: 100%; }

.det-state { font-size: var(--t-md); font-weight: var(--fw-semibold); line-height: 1.4; color: var(--ink); }
.det-state.is-open { color: var(--attention-ink); }

/* ============================================================
   The timeline

   One control for "pick the hours I will host" and "pick the
   hours the seller allows". The readout is the hero: a large live
   hours count, numerals loud and units quiet.
   ============================================================ */
.tl-hero { margin-bottom: var(--s6); text-align: center; }

.tl-metric {
  display: block;
  margin-bottom: var(--s2);
  font-size: var(--t-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-over);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.tl-total { font-size: var(--t-lg); font-weight: var(--fw-medium); line-height: 1; color: var(--ink); }

.tl-total .n {
  font-size: 2.2em;
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.035em;
}

.tl-total .u { color: var(--ink-muted); font-weight: var(--fw-medium); }
.tl-when { margin-top: var(--s3); font-size: var(--t-md); color: var(--ink-soft); font-variant-numeric: tabular-nums; }

.tl { padding: 0 22px; }
.tl-track { position: relative; height: 52px; touch-action: none; }

.tl-surface {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: var(--r-xl);
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--line-strong);
}

/* Hours the person already has. Hatched, not hidden: you can see
   why the bar will not go there. */
.tl-busy { position: absolute; inset: 0; }

.tl-block {
  position: absolute;
  inset-block: 0;
  background: repeating-linear-gradient(
    -45deg,
    var(--danger-soft) 0 6px,
    var(--surface-sunken) 6px 12px
  );
  box-shadow: inset 0 0 0 1px var(--danger-line);
}

.tl-fill { position: absolute; inset: 0; background: var(--accent); clip-path: inset(0 100% 0 0); }
.tl-range { position: absolute; inset: 0; }

/* The touch target is wide and centred on the value; the visible
   knob is smaller and sits inside it, so an older thumb has room
   to land. */
.tl-handle {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 44px;
  margin-inline-start: -22px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  cursor: ew-resize;
  touch-action: none;
}

.tl-knob {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--surface-raised);
  box-shadow:
    0 0 0 1px var(--accent-strong),
    0 3px 10px -2px oklch(24% 0.02 262 / 0.35);
  transition:
    transform var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out);
}

.tl-knob::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--accent); }

/* Under the finger the knob grows and lifts, the way a physical
   control gives back when you press it. */
.tl[data-dragging="start"] [data-h="start"] .tl-knob,
.tl[data-dragging="end"] [data-h="end"] .tl-knob,
.tl[data-dragging="range"] .tl-knob,
.tl-handle:focus-visible .tl-knob {
  transform: scale(1.18);
  box-shadow:
    0 0 0 1px var(--accent-strong),
    0 8px 20px -4px oklch(24% 0.02 262 / 0.4);
}

.tl-handle:focus-visible { outline: none; }

.tl-handle:focus-visible .tl-knob {
  box-shadow:
    0 0 0 1px var(--accent-strong),
    0 0 0 4px var(--accent-soft),
    0 8px 20px -4px oklch(24% 0.02 262 / 0.4);
}

/* The time bubble follows the thumb, so the exact minute is under
   the finger. */
.tl-bubble {
  position: absolute;
  inset-block-end: calc(100% - 3px);
  inset-inline-start: 50%;
  padding: 4px 10px;
  border-radius: var(--r-md);
  background: var(--shell);
  color: var(--shell-ink);
  font-size: var(--t-xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 6px) scale(0.96);
  transform-origin: bottom center;
  transition:
    opacity var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}

.tl-bubble::after {
  content: "";
  position: absolute;
  inset-block-start: 100%;
  inset-inline-start: 50%;
  margin-inline-start: -4px;
  border: 4px solid transparent;
  border-block-start-color: var(--shell);
}

.tl[data-dragging="start"] [data-h="start"] .tl-bubble,
.tl[data-dragging="end"] [data-h="end"] .tl-bubble,
.tl[data-dragging="range"] .tl-bubble,
.tl-handle:focus-visible .tl-bubble { opacity: 1; transform: translate(-50%, 0) scale(1); }

.tl[data-dragging] .tl-handle { cursor: grabbing; }

.tl-ticks { position: relative; height: 20px; margin-top: 10px; }

.tl-tick {
  position: absolute;
  transform: translateX(-50%);
  font-size: var(--t-xs);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tl-hint { margin-top: var(--s5); font-size: var(--t-sm); color: var(--ink-muted); line-height: 1.45; }

.tl-warn {
  margin-top: var(--s3);
  padding: var(--s3);
  border: 1px solid var(--danger-line);
  border-radius: var(--r-md);
  background: var(--danger-soft);
  color: var(--danger-ink);
  font-size: var(--t-sm);
  font-weight: var(--fw-medium);
  line-height: 1.45;
}

@media (min-width: 640px) {
  .sheet { margin: auto; inset-block-end: auto; }
  .sheet-in { border-radius: var(--r-xl); }
  .sheet-head { padding-inline: var(--s5); }
  .sheet-body { padding: var(--s6) var(--s5); }
  .sheet-foot { grid-template-columns: auto auto; justify-content: end; padding-inline: var(--s5); }
  .sheet-foot .btn { width: auto; min-width: 128px; }
  .tl-track { height: 58px; }
  .tl-total { font-size: var(--t-xl); }
}

/* ============================================================
   Desktop composition

   Spans are declared once as a six column intent and folded down
   at each breakpoint. Tiles in a row sit close, rows sit further
   apart, because a row is one question and the next row is a
   different one.
   ============================================================ */
@media (min-width: 720px) {
  .bento { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .tile[data-span="3"] { grid-column: span 2; }
  .jumps { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .row-wide {
    grid-template-columns: 150px minmax(0, 1fr) minmax(0, 1.1fr) auto;
    align-items: center;
    gap: var(--s4);
  }

  .row-offer {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--s4);
  }
}

@media (min-width: 1060px) {
  .bento { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .tile[data-span="3"] { grid-column: span 3; }
}
