/* Transparent, not the old page-sized panel: the wallpaper (.app-wallpaper, fixed behind
   everything) shows straight through, the same idiom Calendar's own .agenda already states.
   A card still draws its own surface (.app-card, .review-item); it is only the FIELD around
   them, and the header/switch text directly on the wallpaper, that stopped drawing one of
   its own. */
.email-review {
  display: flex;
  flex-direction: column;
  background: transparent;
}

.email-review > .app-page,
.email-review > .app-page > .app-page-body {
  flex: 1 1 0;
  min-height: 0;
}

.chat.email-review.review-expanded .email-review {
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
}

.email-review[hidden],
.email-review-detail[hidden] {
  display: none;
}

.review-item-attachments {
  margin-top: var(--space-md);
}

.pdf-viewer {
  position: fixed;
  inset: 0;
  z-index: 46;
  display: flex;
  flex-direction: column;
  background: var(--panel-subtle);
  /* Shown as a manual popover to sit in the top layer above any open modal;
     the rest resets the UA popover chrome so it still covers the whole page. */
  margin: 0;
  border: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  overflow: hidden;
  color: inherit;
}

.pdf-viewer > .app-toolbar {
  flex-wrap: nowrap;
  padding-top: 0.6rem;
  padding-inline: var(--space-r3);
}

.pdf-viewer .app-quiet-button {
  min-height: var(--touch-min);
}

/* The bar's X is .app-dialog-x, which already carries its own var(--touch-min) square. */

/* The load/print failure line and its Retry, on the viewer's own ground under the bar.
   Empty (both children hidden) the row collapses to nothing. */
.pdf-viewer-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding-inline: var(--space-r3);
}

/* The pages themselves are canvases pdf-print.js renders, not an iframe: iOS WebKit shows a
   blank frame for a PDF document, so the app draws every page. Pan and pinch stay available so
   a page can be zoomed; the browser handles the zoom and this scroller the panning. The element
   carries data-zoomable so page-zoom-guard.js leaves its pinch alone. */
.pdf-viewer-pages {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x pan-y pinch-zoom;
  background: var(--panel-subtle);
  /* No bottom inset of its own: .app-fullscreen on the overlay owns it, and this
     padding keeps pages clear of the screen edge. */
  padding: var(--space-md);
}

.pdf-viewer-page {
  display: block;
  margin-inline: auto;
  max-width: 100%;
  height: auto;
  border-radius: var(--card-radius);
  box-shadow: var(--shadow-card);
}

.pdf-viewer-page + .pdf-viewer-page {
  margin-top: var(--space-md);
}

/* The quiet spinner shown from the tap until the first page lands, centred in the field. */
.pdf-viewer-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

.pdf-print-frame {
  position: fixed;
  width: 1px;
  height: 1px;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

/* The Review/Emails switch's own track: a translucent dark ground directly on the
   wallpaper, the reference's own gp-view-switch, rather than the old opaque panel-coloured
   toolbar band this used to be capped by (see the removed comment history for that idiom).
   .app-toolbar-title's empty <strong> still lives here for chat.dom-integration.test.ts's
   own sake (it reads '.email-review-bar strong' and expects it empty); zero width and
   height keep it out of the track's own layout. */
.email-review-bar {
  flex: 0 0 auto;
  flex-wrap: wrap;
  gap: var(--space-xs);
  padding: var(--space-xs);
  background: var(--switch-track-ground);
  border-radius: var(--radius-control);
}

.email-review-bar > .app-toolbar-title {
  display: none;
}

/* The track sat edge to edge (0px from the screen) while every card below it is 17px in, so
   its rounded ends touched the bezel; it takes the cards' own gutter. (At the reading measure
   the 62rem rule further down still centres it.) */
.email-review-bar {
  margin-inline: var(--list-gutter);
}

/* The switch does not overlap the list -- the field starts right under it -- but the field's
   clip edge is flush against the track, so a card scrolled up to it shows as a hard-cut sliver
   between the switch and the next card, which reads as the card showing through the track's
   translucent half. The field's top 10px (its own padding-top, so nothing at scrollTop 0 is
   touched) fades out instead. */
body:not(.wall) .chat .email-review-detail {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 12px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 12px), transparent 100%);
}

/* Review and #email-view-switch are both real buttons in the track now, read as matched
   segments: centred icon-plus-label, each at least 44px tall. .review-view-switch keeps its
   own historical class for the Emails button (renderEmailViewSwitch never changes it), so
   both selectors are named here rather than sharing a new one. */
.review-view-switch-review,
.review-view-switch {
  display: flex;
  flex: 1 1 0;
  min-width: max-content;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  min-height: var(--touch-min);
  padding: var(--space-md);
  color: var(--ink-on-wall-muted);
  background: transparent;
  border-color: transparent;
  border-radius: var(--radius-nested);
  font-size: var(--text-control);
  font-weight: var(--w-title);
  white-space: nowrap;
}

.review-view-switch-review svg,
.review-view-switch svg {
  width: 16px;
  height: 16px;
  flex: none;
}

.review-view-switch-review:hover,
.review-view-switch:hover,
.review-view-switch-review:focus-visible,
.review-view-switch:focus-visible {
  color: var(--ink-heading);
}

/* The selected segment: --panel-subtle plus gold ink, the same "selected pill on a
   translucent track" pairing the reference itself draws. aria-pressed is the single source of
   truth for which button this is (renderEmailViewSwitch sets both at once, so exactly one of
   the two ever matches) -- placed after the hover/focus rule above so the selected pill's own
   colour still wins when that button is also hovered or focused. */
.review-view-switch-review[aria-pressed="true"],
.review-view-switch[aria-pressed="true"] {
  background: var(--panel-subtle);
  color: var(--accent-ink);
  box-shadow: var(--shadow-inset-highlight);
}

.review-arrow {
  flex: none;
  color: var(--muted);
  transition: transform 140ms ease;
}

.meals-proposal-toggle[aria-expanded="false"] .review-arrow {
  transform: rotate(-90deg);
}

/* The count and last-checked line, directly on the wallpaper under the title --
   .app-page-header-subtitle already supplies the on-wall ink, shadow and ellipsis rules;
   this only lets it wrap. */
.review-check-state {
  overflow-wrap: break-word;
  white-space: normal;
}

.mail-howto-gmail-status {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin: 0;
}

/* Shrink factor 100, not 1: this note is the one thing in the bar that can afford to lose
   characters, so it must absorb the whole deficit before the pane's own name beside it gives up
   any. Flexbox shares a deficit in proportion to the shrink factors, so "first" is spelled as a
   large number here rather than by source order. */
.calendar-note {
  flex: 0 100 auto;
  min-width: 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
  font-weight: var(--w-meta);
  line-height: 1.35;
  overflow-wrap: break-word;
  white-space: normal;
}

.calendar-note {
  margin-right: 0.8rem;
}

/* One word, and it must keep both letters: `Off` ellipsised to `O.` says nothing. It
   shares .calendar-note's look but not its willingness to shrink, so at a phone width the
   deficit falls on the sentence beside it, which can afford to lose its tail. It also
   gives up the note's trailing margin, because it is the last thing in the bar.

   The unconfigured case is the one this has to survive. A server with no VAPID key puts a
   whole sentence here instead of a word, and an unshrinkable non-wrapping sentence measured
   436px inside a 390px viewport; Chromium answers a horizontal overrun by inflating the
   layout viewport, which pushes every position: fixed control off the screen. The cap and
   the wrap below bound that sentence and nothing else: `On` and `Off` are a fraction of the
   cap, so they still never wrap, never ellipsise and never give up a character, and
   flex: none is unchanged. */
#notifications-status {
  flex: none;
  max-width: 45%;
  margin-right: 0;
  white-space: normal;
  overflow-wrap: anywhere;
}

.calendar-add-failure {
  color: var(--error);
}

.calendar-proposal-event {
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--line);
}

.calendar-proposal-event h4,
.calendar-proposal-event p {
  margin: 0 0 var(--space-r1);
}

.calendar-proposal-event h4 {
  font-size: var(--text-detail-title);
}

.calendar-event-schedule,
.calendar-event-field {
  color: var(--muted);
}

.event-people {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.person-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-r1);
  min-height: var(--touch-min);
  color: var(--ink);
}

/* A person's colour is set at runtime from the household roster: person.js writes the
   #roster-colors style, mapping each [data-person-key] to --person-color. A key with no
   roster entry gets no wash at all -- the plain surface and the standard border -- rather
   than the shared-household neutral, because an unrecognised name is the opposite of "shared". */

/* The dot carries only the key; the colour arrives through --person-color above. An
   unmapped key leaves --person-color unset, and `transparent` is then the honest result:
   the name still renders, dotless, exactly as an unsaved person's chip always has. */
.person-dot {
  flex: none;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--person-color, transparent);
}

.calendar-scope-summary {
  color: var(--ink);
  font-weight: var(--w-display);
}

.email-review-status,
.meals-status {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-detail-body);
}

/* The pale field the message cards sit on is this whole scroller, not the list inside it: a
   field that stopped at the last card left the panel half tinted and half white, and a list
   that padded itself inside this padding compounded two gutters into one 26px inset. The
   field itself is the shared .app-scroller; only the basis differs, because this pane's
   scroller must not grow past its panel. */
.email-review-detail {
  flex: 1 1 0;
  /* .app-scroller sets overflow-y:auto and leaves overflow-x at its visible default, but
     the CSS spec turns that visible into auto the moment the other axis is non-visible --
     so any child even a pixel wider than this pane becomes horizontally pannable. Setting
     this explicitly removes that surface once nothing inside actually needs it (see the
     overflow-wrap: anywhere rules below); touch-action matches .agenda-days' own
     vertical-only idiom. */
  overflow-x: hidden;
  touch-action: pan-y;
  /* The field's own side gutter, restated where it cannot be lost: the intro line and the
     status text sit on the wallpaper here, not in a card, so a missing inset ran them to
     the screen edge. */
  min-width: 0;
  padding-inline: var(--list-gutter);
}

/* Bare lines in this field (loading/empty/failure status) are on the
   wallpaper, not on a card, so they read in the on-wall ink with its shadow. */
.email-review-status {
  overflow-wrap: anywhere;
}

.email-review-status {
  color: var(--ink-on-wall-muted);
  text-shadow: var(--text-shadow-on-wall);
}

/* The status line and the Connect/Reconnect control share one row: a schedule pause
   names the problem exactly where its remedy sits (renderReviewStatus decides both in
   the same render). The row carries the bottom margin this field's lines otherwise own
   individually, so neither child brings its own into the row. */
.review-status-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-r2);
  margin: 0 0 0.65rem;
}

.review-status-line .email-review-status {
  margin: 0;
}

.email-review-status,
.meals-status,
.today-status {
  margin: 0 0 0.65rem;
}

.review-items[hidden],
.email-list[hidden] {
  display: none;
}

/* Deliberately NOT overflow: hidden, which would clip the header wash to the card's radius for
   free. The header rounds its own top corners instead.

   padding is the card's own --card-pad now, not 0: the header and footer used to sit flush
   against the card's edges, reading as glued to the surface's border rather than inside it, with
   every OTHER child inset by a hand-rolled 12px margin instead. One padding value insets
   everything -- header, subject, summary, highlights, footer -- alike, the reference's own
   .gp-panel shape. */
.review-item {
  position: relative;
  padding: var(--card-pad);
}

.review-item p,
.review-item li {
  margin: 0 0 0.3rem;
  font-size: var(--text-detail-body);
  overflow-wrap: anywhere;
}

/* No border stripe of its own: every card shares the one .app-card surface (rule 01 --
   see the reference, which never colours a failed message's whole panel either), and
   p.review-item-failure below is a quiet muted line with no alarm colour. */
p.review-item-failure {
  color: var(--muted);
  font-size: var(--text-support);
  margin: 0 0 var(--space-sm);
}

.review-item .review-summary {
  margin: 0 0 0;
  color: var(--muted);
  font-size: var(--text-support);
  line-height: var(--leading-detail-body);
}

.review-summary-list {
  margin: 0;
  padding-left: 1.15rem;
}

.review-item .review-summary-list li {
  margin-bottom: var(--space-sm);
  font-size: var(--text-support);
  line-height: var(--leading-detail-body);
}

/* The extracted event: a compact action row separated from the summary by a hairline, the
   reference's own gp-suggested-event, rather than the tinted inset-with-a-left-accent this
   used to be. .review-highlight's own ::before (below) draws the leading gold calendar
   icon -- a generated box, not a real child, because the DOM tests pin
   .review-highlight-main as this row's own first *element* child (firstElementChild), and a
   pseudo-element is invisible to that query while still landing first in the row's own flex
   order. This rule also overrides every one of .app-inset's own properties (see the class
   list in chat.js): the class stays, for email-review-*.dom-integration.test.ts's own
   '.review-highlights.app-inset' check, but the look is this compact on-card row now, not a
   tinted inset box. */
.review-highlights {
  margin: var(--space-lg) 0 0;
  padding: 11px 0 0;
  color: var(--ink);
  background: transparent;
  border-top: 1px solid var(--card-line);
  border-radius: 0;
  font-size: inherit;
}

.review-item .review-highlight + .review-highlight {
  margin-top: var(--space-lg);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--card-line);
}

.review-item .review-highlight {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.15rem 0.6rem;
}

.review-highlight::before {
  content: '';
  flex: none;
  align-self: flex-start;
  width: 17px;
  height: 17px;
  margin-top: var(--space-2xs);
  background-color: var(--accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cline x1='16' x2='16' y1='2' y2='6'/%3E%3Cline x1='8' x2='8' y1='2' y2='6'/%3E%3Cline x1='3' x2='21' y1='10' y2='10'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cline x1='16' x2='16' y1='2' y2='6'/%3E%3Cline x1='8' x2='8' y1='2' y2='6'/%3E%3Cline x1='3' x2='21' y1='10' y2='10'/%3E%3C/svg%3E") center / contain no-repeat;
}

.review-highlight-main {
  flex: 1 1 12rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.review-highlight-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.4rem;
}

/* Colour is .app-row-meta's own (see the class list in chat.js); size steps down one further,
   to the reference's own gp-suggested-event small (a date reads quieter than the title beside
   it, not at the shared row-meta step every OTHER row's meta line uses). */
.review-highlight-meta {
  font-size: var(--text-caption);
}

/* The title is the row's first line, .app-row-title's own weight -- but not its ink: the
   class list also carries .app-key (see chat.js), which reads this row's own extracted date
   or time everywhere else in the app, and coloured the title gold along with it. The event
   here is a whole ROW, not a key datum inside one, so the title reads at the reference's own
   plain white (--ink) with the gold reserved for the calendar glyph beside it; the more
   specific selector overrides .app-key's colour without touching the class list every DOM
   test still pins. Size steps down to match -- the reference's own gp-event-copy strong. */
.review-highlight-title {
  min-width: 0;
  color: var(--ink);
  font-size: var(--text-detail-meta);
  overflow-wrap: anywhere;
}

/* The reference's own gp-add-event: a small square action on a translucent gold ground,
   not the solid accent fill .app-primary-button draws -- the one square action this pane
   has, so it earns its own class rather than composing the shared button. The full "Add
   Event" text stays (chat.dom-integration.test.ts's own email-review suite reads this
   button's textContent for that exact string), even though the reference's own label reads
   just "Add"; the icon carries the rest of the visual compactness. */
.highlight-calendar-preview {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 5px;
  margin-left: 0;
  padding: var(--space-md) var(--space-lg);
  color: var(--accent-ink);
  background: var(--accent-soft);
  border-radius: var(--radius-control);
  font-size: var(--text-detail-meta);
  font-weight: var(--w-title);
  cursor: pointer;
}

.highlight-calendar-preview svg {
  width: 15px;
  height: 15px;
  flex: none;
}

.highlight-calendar-preview:hover,
.highlight-calendar-preview:focus-visible {
  background: color-mix(in srgb, var(--accent) 24%, var(--panel-subtle));
}

.updated-marker,
.unclear-marker {
  margin: var(--space-md) 0.35rem 0.35rem 0;
  padding: 0.05rem 0.35rem;
}

.updated-marker {
  color: var(--accent-hover);
}

.unclear-marker {
  color: var(--muted);
}

/* Every category chip a card shows -- the certainty/update markers above plus the
   highlight's own kind tag (.review-highlight-head's .app-tag) -- reads quieter here than
   .app-tag's base outline: a filled ground instead of a bordered pill, and one step down in
   size, the reference's own quiet corner label rather than a loud outlined badge. --panel is
   the shared "nested inside a card" step .app-card's own comment already names (.app-tag-solid
   draws the same pairing); colour is untouched (the two markers above still need their own),
   since only ground and size are shared across all three. */
.review-item .app-tag {
  background: var(--panel);
  border-color: transparent;
  font-size: var(--text-caption);
}

/* The reference's own gp-mail-title: the email's real subject line, read as this card's
   headline directly under the sender row. Only rendered when it says something the header's
   own name does not already -- see reviewSubjectHeadline in chat.js, which withholds it when
   the subject and the header's name are the same string (the subject was the name's own
   fallback). The more specific selector (over .review-item p's shared 0-margin rule) is what
   lets this one child keep the reference's own 7px lead-in. */
.review-item .review-item-subject {
  margin: 7px 0 var(--space-sm);
  color: var(--ink);
  font-size: var(--text-item);
  font-weight: var(--w-title);
  line-height: var(--leading-detail-tight);
  overflow-wrap: anywhere;
}

/* The card's own closing band, the mirror of .review-item-header at its opening: Show
   original email leads it in gold, and the rest -- Retry, Dismiss, Hide similar -- trail
   at the far right on .review-item-footer-actions' own margin-left: auto, the reference's
   own gp-mail-actions row. */
.review-item-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15rem 0.35rem;
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--card-line);
}

.review-item-footer-actions {
  display: flex;
  flex: none;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.1rem 0.35rem;
  margin-left: auto;
  max-width: 100%;
}

.review-source-link,
.review-quiet-action {
  padding: 0.3rem 0.45rem;
  /* Borderless until hovered: these sit inside a card that already has an edge, so a
     row of outlined buttons in it would read as a second grid of boxes. */
  border-color: transparent;
  font-weight: var(--w-body);
  cursor: pointer;
}

/* min-height, not a taller padding: the visible text stays small (the footer's own
   compactness, matching the reference's gp-mail-actions), but the tap target still clears
   the app's 44px floor. */
.review-quiet-action {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  gap: var(--space-xs);
  color: var(--muted);
  font-size: var(--text-caption);
}

.review-quiet-action svg {
  width: 13px;
  height: 13px;
  flex: none;
}

/* Gold and left-aligned -- the one place this row's own accent goes, the reference's own
   "Show original email ›" link. The chevron is generated content, not a child node: adding
   one would give email-review-*.dom-integration.test.ts's own '.show-original-item' existence
   checks a textContent this file makes no claim about matching either way, so the safer,
   simpler primitive is a pseudo-element neither test nor screen reader ever sees as text. */
.show-original-item {
  margin-right: auto;
  color: var(--accent-ink);
}

.show-original-item::after {
  content: '›';
  margin-left: var(--space-2xs);
}

.review-source-link {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  min-height: var(--touch-min);
  padding: 0;
  text-align: left;
  overflow-wrap: anywhere;
  white-space: normal;
}

.review-source-link:hover,
.review-source-link:focus-visible {
  color: var(--ink);
  background: var(--panel);
}

.review-quiet-action,
.retry-item {
  background: transparent;
}

.review-quiet-action:hover,
.retry-item:hover {
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}

.retry-item {
  color: var(--accent-hover);
}

.retry-item:disabled {
  opacity: 0.6;
  cursor: default;
}

.restore-summary,
.stop-hiding-similar,
.item-operation-status button {
  padding: var(--space-r1) 0.65rem;
}

.stop-hiding-similar {
  margin-left: 0.4rem;
}

.item-operation-status {
  margin: 0;
  padding: var(--space-r2) 0.7rem;
  /* A seam rather than a radius: this one sits flush under the bar above it, so it
     squares off the shared inset's corners and draws the line instead. Its size and ink
     are .app-notice's -- an operation's outcome is a sentence, not a caption. */
  border-radius: 0;
  border-bottom: 1px solid var(--line);
}

.item-operation-status[hidden] {
  display: none;
}

/* Until forwarding works the first-run card replaces the review: the bar, the list field, the
   operation status and the header's check state and gear have nothing to act on (the
   card's Change opens the settings). The ids outrank every class rule that sets a display. */
.email-review.mail-first-run .email-review-bar,
.email-review.mail-first-run .email-review-detail,
.email-review.mail-first-run #item-operation-status,
.email-review.mail-first-run #inbox-settings-open,
.email-review.mail-first-run .review-check-state {
  display: none;
}

.mail-setup,
.mail-asks {
  margin-inline: var(--list-gutter);
}

.mail-setup {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.mail-setup p {
  margin: 0;
}

/* The address grows into the inset's available space while both actions stay at its trailing
   edge; the row wraps when the card is too narrow for all three items. */
.mail-setup-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
}

.mail-setup-address {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  flex: 1 1 auto;
  min-width: 0;
  color: var(--ink);
}

.mail-setup-forward {
  margin-block-start: var(--space-sm);
}

/* The dialog uses one readable row per action. The number is drawn here so the label can wrap
   in the remaining column without falling under a native list marker. */
.mail-howto-steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.mail-howto-step {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-xs);
  color: var(--ink);
  border-radius: var(--radius-control);
}

.mail-howto-step.is-current {
  background: var(--panel);
}

.mail-howto-step.is-complete {
  color: var(--muted);
}

.mail-howto-step-heading {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: var(--space-xs);
}

.mail-howto-number {
  display: inline-grid;
  width: 1.75rem;
  height: 1.75rem;
  flex: none;
  place-items: center;
  color: var(--on-accent);
  background: var(--accent);
  border-radius: 50%;
  font-size: var(--text-detail-meta);
  font-weight: var(--w-title);
}

.mail-howto-step-label {
  flex: 1 1 0;
  min-width: 0;
  overflow-wrap: break-word;
  white-space: normal;
  font-size: var(--text-detail-body);
  font-weight: var(--w-title);
}

.mail-howto-step-status {
  display: inline-flex;
  min-width: 1.75rem;
  flex: none;
  justify-content: center;
  color: var(--accent-ink);
  font-weight: var(--w-title);
}

.mail-howto-step-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xs);
  padding-inline-start: 0;
}

.mail-howto-step-content .app-primary-button {
  width: 100%;
  box-sizing: border-box;
}

.mail-howto-step-content .app-quiet-button {
  align-self: flex-start;
}

.mail-howto-address-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  width: 100%;
  min-width: 0;
  margin: 0;
  padding: 0;
}

.mail-howto-address-box[hidden] {
  display: none;
}

.mail-howto-address {
  box-sizing: border-box;
  min-width: 0;
  flex: 1 1 100%;
  overflow-wrap: anywhere;
  word-break: normal;
  font-size: var(--text-detail-meta);
}

.mail-howto-copy {
  flex: none;
}

.mail-howto-waiting {
  padding-inline-start: 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.mail-howto-connected {
  margin: 0;
  color: var(--accent-ink);
  font-size: var(--text-detail-body);
  font-weight: var(--w-title);
  text-align: center;
}

#mail-howto-dialog:not(.is-connected) #mail-howto-done {
  display: none;
}

.mail-howto-connected + .app-primary-button {
  display: block;
  margin: var(--space-sm) auto 0;
}

.mail-setup[hidden],
.mail-howto-steps[hidden],
.mail-asks:empty {
  display: none;
}

.mail-ask {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
}

.mail-ask > span {
  flex: 1 1 auto;
  overflow-wrap: anywhere;
}

.item-operation-status button {
  margin-left: var(--space-r1);
  color: color-mix(in srgb, var(--accent) 70%, var(--ink));
}

.email-item-dismissed,
.email-item-hidden {
  color: var(--muted);
  background: var(--panel);
}

.email-item-dismissed .email-body,
.email-item-hidden .email-body {
  color: color-mix(in srgb, var(--ink) 72%, var(--muted));
}

/* The tag look itself is app-tag's (see markup); this rule only owns the badge's own
   margin, needed because it sits inline among plain paragraphs rather than in a
   gapped row like the agenda's or a highlight's own tags. */
.email-state-badge {
  margin: 0.2rem 0.35rem 0.2rem 0;
}

.email-hidden-reason,
.email-state-overlap {
  margin: 0.15rem 0;
  color: var(--muted);
  font-size: var(--text-detail-body);
}

.restore-summary,
.stop-hiding-similar {
  margin-top: 0.45rem;
}

.email-item h2 {
  margin: 0 0 var(--space-2xs);
  font-size: var(--text-detail-title);
  font-weight: var(--w-title);
  line-height: var(--leading-detail-tight);
  overflow-wrap: anywhere;
}

.email-metadata {
  margin: 0 0 var(--space-md);
}

/* The message's own control row, above <details>: the primary action first, the quiet
   Open in Gmail link beside it, wrapping rather than truncating on a narrow pane. */
.email-item-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 0.45rem;
}

/* The same gold ink the review card's own footer link carries (see .show-original-item):
   this is the one control in the Emails list that opens the parsed detail rather than the
   raw message, so it reads as the article's primary action, not another quiet link. */
.explore-detail-item {
  color: var(--accent-ink);
}

.email-notes {
  margin: 0.15rem 0;
  color: var(--muted);
  font-size: var(--text-detail-body);
}

.email-item a {
  color: var(--link);
  font-size: var(--text-detail-body);
}

.email-message-details {
  margin-top: 0.35rem;
}

.email-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.email-sources {
  margin: var(--space-r2) 0 0;
  padding: 0 0 0 0.6rem;
  border-radius: 0;
  border-left: 2px solid var(--line-strong);
}

.email-sources .app-card-title {
  margin: 0 0 0.3rem;
}

.email-source {
  margin: 0 0 0.45rem;
}

.email-source-excerpt {
  margin: 0;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
  font-size: var(--text-detail-body);
}

.email-item {
  min-width: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.email-body {
  max-width: 100%;
  margin: 0.45rem 0 0;
  padding: 0.6rem;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
  color: var(--ink);
  border-left: 2px solid color-mix(in srgb, var(--accent) 50%, var(--line));
  /* A quoted message body reads at the caption step, which is .app-inset's own -- this
     used to be a `font:` shorthand carrying a tenth per-surface rem size that the
     typography guard's longhand-only regex could not see. The guard sees a shorthand
     now; the size is simply gone. */
}

/* Defensive scaling for any image or table content rendered into these two Email
   containers, scoped to them only -- not an app-wide rule. Neither element currently
   appears in email content (summaries and the raw body are plain text), but the
   containers' own overflow-x: hidden above only stays honest if nothing that could
   still show up inside them is allowed to force extra width. */
.email-review-detail img,
.email-detail-body img {
  max-width: 100%;
  height: auto;
}

.email-review-detail table,
.email-detail-body table {
  max-width: 100%;
  table-layout: fixed;
}

.email-review-detail td,
.email-review-detail th,
.email-detail-body td,
.email-detail-body th {
  overflow-wrap: anywhere;
}

.calendar-confirmation p,
.calendar-add-failure {
  margin: 0 0 0.55rem;
}

/* The row now carries up to four things -- the checkbox, the event's own fields, the
   Event/Task switch and the reminder group -- and at a phone width they do not fit on one
   line. The row wraps, and the details claim the line with a real basis, so the two
   control groups drop below the text together instead of each being squeezed into a
   column narrow enough to stack its own buttons. Nothing moves at a desktop width, where
   there was room all along. */
.calendar-proposal-event {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* The candidate list's own checkbox, drawn with the app's circular form: a 24px ring
   that fills solid --accent with an --on-accent mark when chosen, the same treatment
   .agenda-task-check, .meals-proposal-choice input, .grocery-check-input and
   .grocery-ingredient-check all draw. margin-top keeps it aligned with the row's first
   text line when align-items: flex-start applies (see .calendar-proposal-event above). */
/* The candidate list's checkbox is the shared .app-check. margin-top is all that is
   left of this rule's own job: keeping the ring aligned with the row's first text line
   when align-items: flex-start applies (see .calendar-proposal-event above). */
.calendar-candidate-choice {
  margin-top: var(--space-r1);
}

/* A long proposal's header: what it holds, how much of it is selected, and the two
   controls that move the whole selection at once. Only rendered above
   CALENDAR_PROPOSAL_GROUP_FROM actions; a short proposal stays a plain list. */
.calendar-proposal-summary {
  margin: 0 0 0.4rem;
  font-size: var(--text-detail-body);
  color: var(--muted);
}

.calendar-proposal-select-controls {
  display: flex;
  gap: 0.4rem;
  margin-bottom: var(--card-gap);
}

/* One operation's disclosure. Built on the same quiet-toggle-over-a-hidden-list shape
   as the agenda's "Completed · N" group, so the two read as one idiom: the list is
   hidden, never unbuilt, and every proposed action is in the document from first render. */
.calendar-proposal-group {
  margin-bottom: var(--card-gap);
}

.calendar-proposal-group-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.calendar-proposal-group-toggle {
  flex: 1;
  min-width: 0;
  text-align: left;
}

.calendar-proposal-group-count {
  color: var(--muted);
}

.calendar-proposal-group-list {
  margin-top: var(--card-gap);
}

.calendar-proposal-group-list[hidden] {
  display: none;
}

.calendar-event-details {
  min-width: 0;
  /* A basis, not just a grow: with `auto` the details shrink to fit whatever the control
     groups demand, which is what left the reminder group a 45px column with its two
     buttons stacked. 12rem is wide enough to read a title on a 390px phone and short
     enough that the controls still share the line on a desktop. */
  flex: 1 1 12rem;
}

.calendar-add {
  /* Ink on the accent fill below, not the page ground -- see --on-accent. */
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
}

/* min-height only: at --text-detail-body a 36px fixed height is one pixel short of the
   line box plus its padding, and the label clips. */
.calendar-proposal-control {
  min-height: 36px;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-control);
  font: inherit;
  font-size: var(--text-detail-body);
  font-weight: var(--w-title);
}

/* Add is the region's one accepted action and keeps .calendar-add's accent fill above; Cancel is the shared .app-quiet-button. */

.calendar-add:disabled {
  opacity: 0.6;
}

.calendar-add-failure {
  margin-top: 0.55rem;
  font-size: var(--text-detail-body);
}

.calendar-confirmation p {
  font-size: var(--text-detail-body);
}

@media (prefers-reduced-motion: reduce) {
  .chat {
    transition: none;
  }
}
