/* The wall keeps the Small sizes whatever this device's stored text size is. */
body.wall {
  --text-scale: 0.875;
  --text-detail-body: 1rem;
  --text-detail-meta: 0.875rem;
  --label-row-min: calc(var(--text-detail-meta) * 1.5);
  --text-detail-title: 1.125rem;
  --text-section: 1.0625rem;
  --text-page-title: 1.875rem;
  --text-item: var(--text-detail-body);
  --text-support: var(--text-detail-meta);
  --text-caption: 0.75rem;
  --text-control: 1rem;
  --text-launcher-label: 0.8125rem;
  --text-input: max(1rem, var(--text-detail-body));
}

/* The side dock keeps the Small label; a bottom dock takes the phone-width label so six labels fit. */
@media (orientation: landscape) {
  body.wall {
    --text-dock-label: 0.875rem;
  }
}

/* The wall route (see docs/architecture/calendar.md, "The wall route"): the same document and the same
   four-week grid a desktop draws, at its own path, with the header, the chat overlay and the
   agenda's own phone/desktop toolbar all put away. Of the command bar only the composer is
   hidden -- the dock below it stays, so whoever walks up to the wall can still leave for
   another app -- and the grid and its permanent Today column beside it are the whole screen. */
body.wall .chat-header,
body.wall #composer {
  display: none;
}

/* No page scroll: the shell fills the viewport instead of centring a bounded column, and the
   only scrollers left standing are the Today column's own body below and the day overlay.
   .chat-upper and .chat-lower need no rule of their own here -- with the header gone and
   every sibling pane hidden by syncAgentView() itself, .chat-upper's content is empty and
   .chat-lower's existing flex: 1 1 0 already gives #agenda the whole of what that leaves,
   exactly the mechanism every other route already relies on. */
body.wall .chat {
  max-width: none;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
}

/* The phone/desktop furniture the wall has no use for: there is no date to jump to and no
   window to step, so Today and the week-step nav go with #agenda's own .app-page-header
   that now holds them both. It stays display: none here too -- nobody is present to read a
   meta line, and left unhidden it would land as an unplaced grid item in body.wall
   #agenda's own two-row grid (below), since it names no grid-row/grid-column of its own. */
body.wall #agenda-strip,
body.wall #agenda-days,
body.wall #agenda .app-page-header {
  display: none;
}

/* #agenda-status takes row 1 across both columns, so a message never
   nudges the grid or the Today column sideways; the grid takes row 2's left column and the
   Today column its right. --wall-today-width is its own token rather than reusing
   --shell-max/--shell-gutter, which size a centred phone/desktop column the wall has
   neither of. The pane's accent top edge goes with the hidden page header above, so the
   kiosk grid's pixel budget is exactly what it was. */
body.wall #agenda {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--wall-today-width, clamp(168px, 21%, 280px));
  grid-template-rows: auto minmax(0, 1fr);
  gap: 0.5rem;
  padding: 0.5rem;
  height: 100vh;
  height: 100dvh;
  border-top: 0;
}

body.wall .agenda-status {
  grid-column: 1 / -1;
  grid-row: 1;
}

/* An ordinary day says nothing in either line; without this an empty <p> still spends a
   line's height on row 1, which the wall -- unlike the phone or the desktop, which scroll --
   has no slack for. The same trap .agenda-grid[hidden] exists for, restated here because it
   is what makes row 1 disappear entirely on a quiet day. */
body.wall .agenda-status:empty {
  display: none;
}

/* The grid used to keep the desktop grid's own geometry and --text-detail-* type wholesale,
   on the theory that a TV read from across a room is physically larger than a desktop
   monitor at the same CSS pixels and so already reads at a distance. A real photo of the
   Fire TV Stick and a real headless-Chromium measurement against live calendar data both
   said that theory does not hold for a 28-cell month: 900x550 drew as few as 2 chips per
   cell, folded most of the month into "+N more", and broke titles mid-word ("Bowlin / g").
   So the wall now has its own denser type throughout this block -- lighter gap and padding
   here, and the cell/weekday/chip sizes below -- sized for a 28-cell grid rather than
   borrowed from the desktop's four-week grid, which never has to share a monitor with 27
   neighbours the way this does. */
body.wall .agenda-grid {
  grid-column: 1;
  grid-row: 2;
  min-height: 0;
  gap: 0.25rem;
}

/* Tighter than the desktop grid's own 10px/3px: less padding and a smaller inner gap buy
   back chip room a 28-cell month cannot otherwise spare. gap here overrides the 3px
   .agenda-cell inherits from the base rule above for the same reason. */
body.wall .agenda-cell {
  padding: 6px;
  gap: 2px;
}

/* A column beside the grid, not a pane of its own: a left border is enough to separate it,
   since the grid already carries the accent, the weekend tint and today's own border.
   Round 3, item 3: the Fire TV's own microphone/voice overlay paints over the top right of
   the screen, exactly where this column's title sat -- 34px from the top, measured against
   fad0e41 with a real headless Chromium at all four measured viewports (the figure does not
   vary by viewport: every contributor above it is a fixed px value, not a percentage). The
   padding-top below therefore rises from 6px to 34px, and the 28px that adds is chosen for
   headroom past the 56px floor rather than measured off the set; the measured result is 62px at
   every one of 900x550, 1024x600, 1280x720 and 1920x1080, and it moves nothing else: the
   grid on the left is untouched (.agenda-grid above keeps its own gap and padding), and none
   of the column's six real entries lose their place -- all six still render without
   scrolling at every measured viewport, before and after (see wall.dom-integration.test.ts
   and the implementer's report for the measured numbers). .agenda-wall-today-body below
   still takes flex: 1 1 0 and fills whatever height this leaves it. */
body.wall .agenda-wall-today {
  grid-column: 2;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  min-height: 0;
  gap: 0.25rem;
  padding: 34px 0 6px 10px;
  border-left: 1px solid var(--card-line);
}

/* Wraps rather than truncating: "Today, Thursday 17 September" does not fit one line at
   900x550 (a 189px column), and a screen whose whole job is saying what today is must not
   ellipsise the month away. flex: none still holds -- the column has the vertical room for
   two lines there, and it is the scrolling body below, not this title, that gives up height.
   13px rather than --text-detail-title for the same reason the grid's own type dropped: this
   is a TV read from across a room, and what that screen has too little of is room, not
   size. */
body.wall .agenda-wall-today-title {
  flex: none;
  margin: 0;
  color: var(--ink);
  font-size: calc(0.8125rem * var(--text-scale));
  line-height: 1.25;
  font-weight: var(--w-title);
  white-space: normal;
}

/* The "scrollable, no +N" half of the column's whole reason to exist: every entry gets a
   row here, however many there are, and this is the one place that scrolls instead of
   clipping or counting. */
body.wall .agenda-wall-today-body {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

body.wall .planning-block {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--card-line);
}
body.wall .planning-block .app-section-label {
  margin: 0;
  font-size: calc(0.6875rem * var(--text-scale));
}
body.wall .planning-block[hidden] { display: none; }
body.wall #planning-groceries { max-height: 40%; overflow: hidden; }
body.wall .planning-meal-title {
  margin: 0;
  font-size: calc(0.8125rem * var(--text-scale));
  line-height: 1.25;
  overflow-wrap: anywhere;
}
body.wall .planning-groceries-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: calc(0.75rem * var(--text-scale));
  line-height: 1.25;
  color: var(--ink);
}
body.wall .planning-groceries-list .app-empty {
  margin: 0;
  padding: 0;
  font-size: calc(0.75rem * var(--text-scale));
}
body.wall .planning-groceries-list li { overflow-wrap: anywhere; }

/* The column's rows take the grid chip's own denser type. */
body.wall .agenda-wall-today-row.agenda-chip {
  font-size: calc(0.6875rem * var(--text-scale));
  line-height: 1.3;
  padding: 2px 5px;
}

/* The grid's own denser type, continued: weekday, date and chip sizes sized for a 28-cell
   month rather than the desktop grid's --text-detail-* tokens. .agenda-grid-weeks's own
   gap (see the base rule above) only widens to 0.55rem inside the @media (min-width:
   68.75rem) block further down, which the wall -- 900px to 1280px -- matches inconsistently;
   without a rule of its own here the wall's own cell gap would silently change between
   viewports it is never actually laid out at. */
body.wall .agenda-grid-weeks { gap: 4px; }
body.wall .agenda-grid-weekday { font-size: calc(0.6875rem * var(--text-scale)); letter-spacing: 0.03em; }
body.wall .agenda-cell-date { gap: 0.2rem; }
body.wall .agenda-cell-day { font-size: calc(0.75rem * var(--text-scale)); line-height: 1.15; }
body.wall .agenda-cell-month { font-size: calc(0.625rem * var(--text-scale)); }
body.wall .agenda-cell-chips { gap: 2px; }
/* Wall grid chips keep the shared flex layout so the title can wrap beneath the time when
   the cell is narrow. */
body.wall .agenda-cell .agenda-chip {
  display: flex;
  gap: 0.2rem;
  font-size: calc(0.625rem * var(--text-scale));
  line-height: 1.3;
  padding: 0 4px;
  border-radius: var(--radius-control);
}

/* Mandatory, not decoration: fitAgendaGridChips (agenda.js) trims an overflowing chip by
   setting its hidden attribute, and the base .agenda-chip[hidden] rule (0,2,0) is what
   turns that into display: none -- but body.wall .agenda-cell .agenda-chip above is
   (0,3,1), so once it declares its own display, it already outranks that base rule and a
   hidden wall grid chip would render anyway. This is the same cascade trap the two
   --person-edge padding-left restatements existed for before the wash replaced them; the
   property is different (display, not padding-left) but the reason to restate it here,
   at equal or higher specificity, is the same one. */
body.wall .agenda-cell .agenda-chip[hidden] {
  display: none;
}

/* Second feedback round: every coloured chip on the wall reads as one flat tint, never the
   3px .agenda-chip[data-person-edge] stripe defined earlier in this file -- read from
   across a room, that stripe showed as a lone coloured mark beside an otherwise white chip,
   while a single-person chip took a wash. In
   wall mode, renderAgendaGridChip sets this instead of --person-edge/--person-tint for one
   or more named people with a colour, so both counts go through the one wash path
   (personWashGradient) and can never look inconsistent with each other again. background-size:
   100% 100% is what makes the hard-stopped gradient cover the whole chip rather than the
   3px sliver --person-edge painted. */
body.wall .agenda-chip[data-person-wash] {
  background-image: var(--person-wash);
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

body.wall .agenda-cell-more { font-size: calc(0.625rem * var(--text-scale)); }

@media (max-width: 30rem) {
  /* The centered choice card keeps big tap targets; none of these controls are full width. */
  .choice-row-label {
    font-size: var(--text-section);
  }

  .chat {
    --shell-pad-bottom: 0.75rem;
    padding: calc(var(--safe-top) + var(--space-xs)) 0 calc(var(--shell-pad-bottom) + var(--safe-bottom));
    gap: var(--shell-gap);
    border-right: 0;
    border-left: 0;
    border-radius: 0;
  }

  /* The Library's controls stack full-width below the app's phone breakpoint. flex-wrap
     alone already folds the pair onto two lines, but only stacking makes each a whole
     line: sharing 390px, the filter's refusal to shrink is what clipped the search box
     beside it. */
  .library-controls {
    flex-direction: column;
    align-items: stretch;
  }

  /* The 14rem flex-basis above is a width hint for the desktop row; in this
     block's column direction flex-basis resolves against height instead, so
     without this reset the stacked search field renders 14rem (224px) tall
     with nothing in it. Qualified by its parent because the base .library-search rule
     sits later in this file: at equal specificity it would win and undo the reset. */
  .library-controls .library-search {
    flex: 0 0 auto;
    width: 100%;
  }

  /* The search field now lives in an .app-search row (with its Clear button): the row is the
     stacked flex item, and the field keeps growing inside it. */
  .library-controls .app-search {
    flex: 0 0 auto;
  }

  .library-controls .app-search > .library-search {
    flex: 1 1 0;
  }

  /* The .app-field-row 9rem flex-basis would become a height in this column layout (the type select rendered 144px tall). */
  .library-controls.app-field-row > .app-field {
    flex: 0 0 auto;
  }

  /* A grid is a grid on the widths that have room for one; on the phone every column
     count is one column. Stated once for every caller -- the app's own layouts and a
     drafted page alike. Both selectors because the 3-column rule would otherwise
     outrank a bare .app-grid here. */
  .app-grid,
  .app-grid[data-columns="3"] {
    grid-template-columns: minmax(0, 1fr);
  }

  button {
    padding-inline: 1rem;
  }

  .icon-button {
    padding: 0;
  }

}

/* The two widths this app is actually used at, beyond the phone it was built for.
   1100px is where the shell widens and Calendar switches to its four-week grid; 1920px is
   the TV, which is not a bigger desktop but a screen read from across a room.
   They are literals because a media query cannot read a custom property. */
@media (min-width: 68.75rem) {
  :root {
    --shell-max: 100rem;
    --shell-gutter: 1.5rem;
  }

  /* The header spans the full width above the two columns; both keep to the same sensible
     reading measure centred in the pane rather than stretching edge to edge at this width. */
  .today-header,
  .today-body {
    max-width: var(--content-max);
    margin-inline: auto;
  }

  /* Every other flex-column page gets the same column, so headers and content line up from
     page to page. Calendar (two-pane grid), the launcher (own measure), Browser (wants the
     width) and Today, Inbox and Groceries (their own rules) are deliberately left out. */
  .chat-lower > section:is(#meals-plan, #household-facts, #weather, #timers, #podcasts, #music, #library, #photos, #view, #settings) > * {
    width: 100%;
    max-width: var(--content-max);
    margin-inline: auto;
    box-sizing: border-box;
  }

  /* A header one level inside the column wrapper keeps the column's own edge, like the headers that are the column's direct children. */
  #settings-root > .app-page-header,
  #music-overview > .app-page-header {
    margin-inline: 0;
  }

  /* Today's two columns: the day's own work on the left, the inbox on the right, at the
     40/60 split a task title and an email subject actually need. The columns are real boxes
     here rather than the pass-through they are on a phone, so each stacks its own groups and
     both section headings start on the same line. minmax(0, …) on both tracks because a
     long unbroken subject would otherwise push a 3fr track past its share.

     The second track only exists when there is something to put in it: today.js appends a
     column wrapper only for a column that has a group, so :has() asks the DOM rather than
     leaving a 60% hole on a day with no email. */
  .today-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 1.5rem;
  }

  .today-body:has(> .today-column-primary):has(> .today-column-secondary) {
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  }

  .today-column {
    display: flex;
    flex-direction: column;
    gap: var(--rhythm-card-card);
    min-width: 0;
  }

  /* The empty day and a failed read append their one line straight to the body, with no
     column around it; it takes the whole width rather than a 40% track. */
  .today-body > .app-empty {
    grid-column: 1 / -1;
  }

  /* The four-week grid replaces the scrolling day list at this width: the same 28 dates a
     week strip used to index, laid out so a month of the household's plans is read at a
     glance instead of scrolled through. The grid's geometry lives in the base rules, so
     this block only tunes its measures -- a little more air between the cells than the
     base gap, and a little more room inside each one. */
  .agenda-grid-weeks {
    gap: 0.55rem;
  }

  .agenda-cell {
    padding: 10px;
  }

  /* The ordinary grid's own Today panel takes a side column beside the weeks at this width,
     where the wall's own #agenda already runs a two-column grid of its own with a different
     width and different rules (see body.wall #agenda). body:not(.wall) keeps the two
     provably apart: a body can never carry both, so this can never reach the wall's markup,
     however wide a wall screen measures -- docs/architecture/calendar.md notes the wall's own sizes (900px
     to 1280px) straddle this exact breakpoint inconsistently, which is exactly why this is
     scoped by class rather than left to the media query alone. .agenda-grid itself already
     owns the flex:1/min-height:0 sizing that fills the column; this only changes how its own
     two existing children (the weekdays row and the weeks grid) and the new panel share it. */
  body:not(.wall) .agenda-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(220px, 26%, 340px);
    grid-template-rows: auto minmax(0, 1fr);
    column-gap: 1rem;
  }

  /* Mandatory, not decoration: the base .agenda-grid[hidden] rule (0,2,0) would otherwise be
     outranked by body:not(.wall) .agenda-grid above (0,2,1) once that rule names its own
     display, exactly the cascade trap the wall's own [hidden] restatements exist for (see
     body.wall .agenda-cell .agenda-chip[hidden] further up). Without this, the list layout's
     hidden grid would render anyway at this width. */
  body:not(.wall) .agenda-grid[hidden] {
    display: none;
  }

  body:not(.wall) #agenda-grid-weekdays {
    grid-column: 1;
    grid-row: 1;
  }

  body:not(.wall) #agenda-grid-weeks {
    grid-column: 1;
    grid-row: 2;
  }

  /* Spans both of the grid's own rows, so the panel reads as tall as the weekday row plus
     the weeks beside it, not just the weeks row alone. */
  body:not(.wall) .agenda-today-panel {
    grid-column: 2;
    grid-row: 1 / -1;
    min-height: 0;
    padding-left: 1rem;
    border-left: 1px solid var(--card-line);
  }

  /* The stacked/kiosk rule above bounds the body to 35vh so a dense today cannot crowd the
     grid off the stacked layout; beside the grid the panel has its own full column instead,
     so that bound is lifted and the section list is what scrolls if today genuinely does not
     fit. */
  body:not(.wall) .agenda-today-panel-body {
    max-height: none;
    flex: 1 1 0;
  }

  /* The header band, tightened for a screen that is shorter than it is wide: a 900px-tall
     window spent about an eighth of its height on the header and a week strip before the
     first day. The phone keeps its own measures untouched -- it has the height to spare and
     not the width. */
  #agenda .app-page-header {
    padding-top: 0.35rem;
    padding-bottom: 0.2rem;
  }

  .agenda-strip {
    padding: 0.2rem 0.6rem 0.45rem;
  }

  /* Email's content takes a reading measure on a wide screen while the field it sits on
     stays the full scroller. 62rem is about 95 characters at the detail body size -- wide
     enough for a summary card's two columns of metadata, narrow enough that the eye finds
     the next line. The child selector reaches every direct child at once: the status line,
     the failure line, the review list, the email list and the bound note, so a new one
     inherits the measure instead of needing a rule. */
  .email-review-detail > * {
    max-width: var(--content-max);
    margin-inline: auto;
  }

  /* The header and the Review/Emails switch sit outside .email-review-detail (they scroll
     with the page, not inside its own field) and so never picked up the reading measure
     above: at this width they stretched to the full shell while the cards beneath them held
     to the column, reading as two different columns stacked on each other. Same measure, same
     centring, so the switch and the header line up with the cards below them. #email-review
     is a flex column, where auto side margins switch off the cross-axis stretch and
     shrink-wrap a child to its content (the header bunched mid-screen), so each child takes
     the column's full width explicitly. */
  #email-review > .app-page,
  #email-review > .app-page > .app-page-header,
  #email-review > .app-page > .app-page-body > .email-review-bar {
    width: 100%;
    max-width: var(--content-max);
    margin-inline: auto;
    box-sizing: border-box;
    align-self: stretch;
  }

  /* Groceries takes the same reading-measure shape Email's field above does, at a list's
     own narrower measure: a shopping list is one column of short lines, and at the shell's
     full 100rem a wide screen stretched its rows into a scan across the whole pane. The
     scroller's own page ground still runs edge to edge -- only the content centres. */
  .groceries > * {
    width: 100%;
    box-sizing: border-box;
    max-width: var(--content-max);
    margin-inline: auto;
  }

  /* Dinner plan takes the larger share; Saved recipes, which is read occasionally rather
     than worked in, takes the smaller one beside it. */
  .meals-body {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    align-items: start;
    column-gap: 1.5rem;
  }

  .meals-column {
    display: block;
    min-width: 0;
  }

  /* The recipe dialog stands its two halves side by side at the same breakpoint Meals'
     own pane stands the plan beside its aside: the facts and the ingredients on the left,
     the instructions on the right, in a widened dialog. Below this width the dialog is
     the single-column modal it has always been -- same markup, one breakpoint. */
  .recipe-dialog {
    width: min(64rem, calc(100% - 3rem));
  }

  .recipe-body .recipe-detail-columns {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: 1.4rem;
    align-items: start;
  }

  .recipe-body .recipe-detail-steps {
    margin-top: 0;
  }

  /* The store sections side by side when the width is there. auto-fill, not a fixed count:
     one category takes one track and sits at the pane's left edge with nothing invented to
     balance it, and the 62rem cap means two columns at most, never a thin third. The groups
     are the same sections in the same order -- a grid lays them out across and then down, so
     document order, reading order and tab order are one and the same, exactly as they are in
     the single column.

     The base rule spaces groups with a top margin on all but the first. In a grid that margin
     would land on whichever group happens to start the second column, so the rhythm becomes a
     row-gap here and the margin is dropped. */
  .grocery-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr));
    align-items: start;
    max-width: 62rem;
    column-gap: 2rem;
    row-gap: 0.9rem;
  }

  /* This one names the list, not just the group pair, because the base rule it must outrank
     sits further down the file than this block does: at equal specificity the later base rule
     would win, and the margin would survive into the grid. */
  .grocery-list .grocery-group + .grocery-group {
    margin-top: 0;
  }

  /* The empty list's one line takes the whole width rather than a half track. */
  .grocery-list > .app-empty {
    grid-column: 1 / -1;
  }
}

@media (min-width: 120rem) {
  /* Read from a sofa, not from a desk: one step up on the detail scale and on the shell's
     own inset, and every control at 48px rather than 40-44. The type moves through the
     --text-detail-* tokens on purpose -- no rule on any pane names a size of its own, and
     detail-typography.test.ts enforces exactly that. Today keeps the two columns the
     desktop block gives it and the agenda keeps the same four-week grid the desktop block
     gives it, gaining only larger type and taller rows: a wider screen here is never a
     different layout. */
  :root,
  body.wall {
    --shell-gutter: 2rem;
    --text-detail-meta: 1rem;
    --text-detail-body: 1.125rem;
    --text-detail-title: 1.375rem;
    --list-lead: 88px;
    --card-pad: 16px;
    --card-gap: 10px;
    --list-gutter: 16px;
  }

  .icon-button {
    width: 48px;
    min-width: 48px;
    min-height: 48px;
  }

  /* The dock keeps the same four-column grid here too, gaining only a taller floor. */
  .dock-button {
    min-height: 48px;
  }

  .app-quiet-button,
  .app-pill,
  .agenda-today {
    min-height: 48px;
  }

  /* The TV gets the same grid with more room in each cell, never a different layout. */
  .agenda-cell {
    padding: 14px;
  }

  .agenda-chip {
    padding: 4px 8px;
  }
}
