/* ============================================================
   APP — layout for the resident screen. Everything visual comes
   from the design tokens; this file only places things.
   ============================================================ */

/* Each step swaps the body for a short skeleton, which can drop the scrollbar
   and put it back. Reserving its width keeps "›" where the thumb left it. */
html { scrollbar-gutter: stable; }

#root {
  max-width: 32rem;
  margin: 0 auto;
  padding: var(--space-4) var(--space-3) var(--space-7);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* The tabs, then the chosen space's card: the card's neck rises through
   the gap between them, so it is told how tall that gap is. */
.app-spaces:empty, .app-space:empty, .app-notices:empty { display: none; }
/* Set on the card itself: its own default (the gap under a bare row of
   tabs) would otherwise win over anything it inherits. */
.app-space .ssb-spacecard { --gap-above: var(--space-4); }

/* Known problems, inside the space card, between its name and its actions. */
.app-problems:empty { display: none; }
/* The same problems as one line, "2 known problems": only a laptop shows
   it, where the calendar needs the room (below). A count that opens in
   place to what it counts (STYLE.md, Gaps), drawn as the problems' own
   ruled block: the attention edge, the wrench, the count. */
.app-problems__line {
  --ring-gap: calc(-1 * var(--ring-width));
  display: none;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: var(--touch-min);
  padding: 0 var(--space-3);
  border: 0;
  /* The frame's attention edge, drawn again over the line's own fill. */
  box-shadow: inset 3px 0 0 var(--attention-line);
  background: var(--surface);
  color: var(--text-strong);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--fw-bold);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease);
}
.app-problems__line > span { flex: 1 1 auto; }
.app-problems__line > .ssb-icon:first-child { color: var(--attention-text); }
.app-problems__line > .ssb-icon:last-child { color: var(--text-muted); transition: transform var(--dur-base) var(--ease-out); }
/* Pressed: the attention colour's own fill, at once, and the arrow dips. A
   row this wide does not shrink (a scale reads as the row jumping). */
.app-problems__line:active { background: var(--attention-fill); }
.app-problems__line:active > .ssb-icon:last-child { transform: translateY(2px); }
/* Open: the arrow turns, and the list hangs under the line in one frame. */
.app-problems__line[aria-expanded="true"] > .ssb-icon:last-child { transform: rotate(180deg); }
@media (hover: hover) and (pointer: fine) {
  .app-problems__line:hover { background: var(--surface-hover); }
  .app-problems__line:active { background: var(--attention-fill); }
}

/* The report sheet: what is already reported, then the one box. */
.app-report__already {
  margin: var(--space-3) 0 var(--space-1);
  font-size: var(--text-sm);
  font-weight: var(--fw-bold);
}
.app-report { margin-top: var(--space-4); }
.app-report__privacy {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-body);
}
.app-report__privacy > .ssb-icon { flex-shrink: 0; }
.app-report textarea { resize: vertical; min-height: calc(var(--touch-min) * 2); }

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

/* The view switch, and the way back to today beside it. */
.app-controls__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.app-body {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  min-height: 12rem;
}
/* The month grid needs breathing room the slot list doesn't. */
.app-body > .ssb-month { padding: var(--space-3); }
.app-body > div:not(.ssb-month, .ssb-tgrid) { padding: var(--space-3); }
.app-body > ul { padding: 0; }
/* The week needs every pixel across a phone for its seven columns, and ends
   at its last row: the party room's one row is not left in a tall box. */
.app-body > .ssb-tgrid { padding: var(--space-2) var(--space-1); }
.app-body:has(> .ssb-tgrid) { min-height: 0; }
.app-body > ul > li:last-child .ssb-slot { border-bottom: 0; }

/* A view chosen with the switch fades in (app.js, enterView). */
.app-body[data-entering] > * { transition: opacity var(--dur-base) var(--ease-out); }
@starting-style {
  .app-body[data-entering] > * { opacity: 0; }
}
/* The day under the month; empty, and no space, in every other view. */
.app-day:empty { display: none; }

.app-footer {
  font-size: var(--text-xs);
  color: var(--text-faint);
  text-align: center;
}

/* A tablet gets a roomier column; the phone's layout still fits it. */
@media (min-width: 640px) {
  #root { max-width: 36rem; padding-inline: var(--space-4); }
}

/* ---------- A laptop ---------------------------------------------------
   The chosen space is a frame in its own colour around its own calendar:
   its band across the top, the date and the calendar inside. The spaces are
   a list on the left, and the chosen one runs into the frame with the same
   edge, so the space and what it shows read as one thing (Ivan, 2026-10-20:
   two columns side by side had "no natural connection between them").
   The board's notices are one line across the top. design/flows/laptop-layout.md.
   Below 900px the two wrappers are not boxes and the phone's order stands. */
.app-side, .app-frame { display: contents; }

@media (min-width: 900px) {
  #root {
    max-width: 78rem;
    padding-inline: var(--space-5);
    display: grid;
    grid-template-columns: 15rem minmax(0, 1fr);
    grid-template-areas: "bar bar" "notices notices" "side frame" "foot foot";
    column-gap: 0;
    row-gap: var(--space-4);
    align-items: start;
  }
  /* No notices: no row for them, or its two gaps would double the space. */
  #root:has(> .app-notices:empty) { grid-template-areas: "bar bar" "side frame" "foot foot"; }
  .app-header { grid-area: bar; }
  .app-notices { grid-area: notices; }
  .app-footer { grid-area: foot; }
  /* The header has the room: the apartment is named in full. */
  .app-header .ssb-account__who > span { max-width: 16rem; }

  /* One space: no list, and the frame takes the whole width. */
  .app-side:has(> .app-spaces:empty) { display: none; }
  #root:has(.app-spaces:empty) .app-frame { grid-column: 1 / -1; }

  /* The spaces, as a list (.ssb-tabs--side), and the chosen space's frame
     (.ssb-spaceframe): their looks are in components.css. */
  .app-side { grid-area: side; display: block; min-width: 0; }

  /* The first row, chosen, is flush with the frame's top: the frame's
     corner there is square (its curve above is left out in components.css,
     .ssb-tabs--side). */
  #root:has(.app-side .ssb-tab:first-child[aria-pressed="true"]) .app-frame { border-top-left-radius: 0; }

  /* The frame. The card's parts are placed in it directly: its band on
     top, then one row with its problems (as one line) and its actions,
     then the calendar. The calendar keeps the whole width: beside a side
     column under 1200px the party room's week tiles squeezed to four lines. */
  .app-frame {
    grid-area: frame;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "head head" "middle actions" "controls controls" "body body" "day day";
    column-gap: var(--space-3);
    min-width: 0;
    padding-bottom: var(--space-4);
  }
  .app-frame .app-space,
  .app-frame .ssb-spacecard { display: contents; }
  .app-frame .ssb-spacecard::before { display: none; }
  .app-frame .ssb-spacecard__head { grid-area: head; border-radius: 0; }
  .app-frame .ssb-spacecard > :not(.ssb-spacecard__head) { border: 0; border-radius: 0; }
  .app-frame .ssb-spacecard__actions {
    grid-area: actions;
    align-self: start;
    margin: var(--space-3) var(--space-4) 0 0;
  }
  .app-frame .ssb-spacecard__action { padding: 0 var(--space-3); }
  /* The card's own frame is gone, so the actions strip draws its own. */
  .app-frame .ssb-spacecard > .ssb-spacecard__actions {
    border: 1px solid var(--line);
    border-radius: var(--radius);
  }
  .app-frame .app-controls { grid-area: controls; padding: var(--space-4) var(--space-4) 0; }
  .app-frame .app-body { grid-area: body; margin: var(--space-3) var(--space-4) 0; }
  .app-frame .app-day { grid-area: day; margin: var(--space-3) var(--space-4) 0; }
  /* Beside the calendar there is room to read a problem whole. */
  .app-frame .ssb-problems__text { -webkit-line-clamp: 6; line-clamp: 6; }

  /* The problems as one line, opening in place to the list under it, the
     two in one frame with the attention edge. The space card's strip of
     actions sits beside it. */
  .app-frame .ssb-spacecard > .app-problems {
    grid-area: middle;
    align-self: start;
    margin: var(--space-3) 0 0 var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: inset 3px 0 0 var(--attention-line);
    background: var(--surface);
    overflow: clip;
  }
  .app-frame .app-problems__line { display: flex; }
  .app-frame .app-problems > .ssb-problems { display: none; }
  .app-frame .app-problems[data-open] > .ssb-problems {
    display: block;
    padding-top: 0;
    border: 0;
    box-shadow: none;
    background: transparent;
  }
  .app-frame .app-problems[data-open] .ssb-problems__head { display: none; }
}

/* From 1200px a side column fits with about 600px left for the calendar:
   the space's actions and its problems, in full, sit beside it, and the
   date and the calendar start right under the band. A date tapped in the
   month opens its day in that column, beside the month (design-taste 7),
   level with the month's top, its pointer at the date, in the problems' place;
   they stay, as their one line under it. */
@media (min-width: 1200px) {
  .app-frame {
    grid-template-columns: minmax(0, 1fr) 17rem;
    grid-template-rows: auto auto auto 1fr;
    grid-template-areas: "head head" "controls actions" "body day" "body middle";
  }
  .app-frame .ssb-spacecard__actions {
    grid-auto-flow: row;
    margin: var(--space-4) var(--space-4) 0 0;
  }
  .app-frame .ssb-spacecard__action { justify-content: flex-start; }
  .app-frame .ssb-spacecard__action + .ssb-spacecard__action { border-left: 0; border-top: 1px solid var(--line); }
  /* The month keeps its own height whatever the column beside it holds. */
  .app-frame .app-body { margin-right: 0; align-self: start; }
  .app-frame .app-day { margin: var(--space-3) var(--space-4) 0 0; }
  .app-frame .ssb-spacecard > .app-problems { margin: var(--space-3) var(--space-4) 0 0; }

  /* No day open: the problems in full, as the phone shows them. */
  .app-frame:not(:has(.app-day > .ssb-monthday)) .ssb-spacecard > .app-problems {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
    overflow: visible;
  }
  .app-frame:not(:has(.app-day > .ssb-monthday)) .app-problems__line { display: none; }
  .app-frame:not(:has(.app-day > .ssb-monthday)) .app-problems > .ssb-problems { display: block; }
  .app-frame:not(:has(.app-day > .ssb-monthday)) .app-problems .ssb-problems__head { display: flex; }

  /* The day beside the month: level with the month's top, its pointer at
     the date's row (app.js, placeDay, which sets both lengths). It comes in
     from the month's side. */
  .app-frame .app-day .ssb-monthday {
    --beside-top: 0px;
    --point: 50%;
    margin-top: var(--beside-top);
  }
  .app-frame .app-day .ssb-monthday[data-closing] { transform: translateX(-8px); }
  /* Its pointer on the side that faces the month, at the date's row, in the
     date ring's accent, reaching across the gap to the month's edge. */
  .app-frame .app-day .ssb-monthday__notch {
    left: auto;
    right: 100%;
    bottom: auto;
    top: 0;
    width: var(--space-4);
    height: 0;
    transform: translateY(var(--point));
  }
  .app-frame .app-day .ssb-monthday[data-placing] .ssb-monthday__notch { transition: none; }
  .app-frame .app-day .ssb-monthday__notch::before {
    left: auto;
    right: -9px;
    top: 0;
    width: 18px;
    height: 18px;
    transform: translateY(-50%) rotate(-45deg);
  }

  /* A narrow column: each window is two lines, its time over its length and
     name ("3 hours · Morning"), and its state at the end. */
  .app-frame .app-day .ssb-slot {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "time time state" "length name state";
    align-items: baseline;
    column-gap: var(--space-1);
    row-gap: 0;
  }
  .app-frame .app-day .ssb-slot__when { display: contents; }
  .app-frame .app-day .ssb-slot__time { grid-area: time; }
  .app-frame .app-day .ssb-slot__length { grid-area: length; }
  .app-frame .app-day .ssb-slot__name { grid-area: name; font-size: var(--text-xs); }
  .app-frame .app-day .ssb-slot__when:has(.ssb-slot__length) + .ssb-slot__name::before { content: "· "; }
  .app-frame .app-day .ssb-slot__state { grid-area: state; align-self: center; margin-left: var(--space-2); }
}
@media (min-width: 1200px) and (prefers-reduced-motion: no-preference) {
  @starting-style {
    .app-frame .app-day .ssb-monthday { opacity: 0; transform: translateX(-16px); }
  }
}
@media (min-width: 1200px) and (prefers-reduced-motion: reduce) {
  .app-frame .app-day .ssb-monthday__notch { transition: none; }
}

/* A window with places, in its sheet (design/briefs/places-per-window.md). */
.app-places__count {
  margin: var(--space-2) 0 0;
  font-size: var(--text-md);
  color: var(--text-body);
}
.app-places__count b {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--fw-heavy);
  color: var(--text-strong);
}
.app-places__tiles { margin-top: var(--space-3); }
.app-places__held {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.app-places__mine {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}
.app-places__why { margin: var(--space-2) 0 0; font-size: var(--text-sm); color: var(--text-body); }
