diff --git a/resources/views/email.phtml b/resources/views/email.phtml index 0d936b5..3ef724d 100644 --- a/resources/views/email.phtml +++ b/resources/views/email.phtml @@ -375,35 +375,36 @@ $section_kicker_style = 'margin:0 0 18px;' . 'font-style:italic;font-weight:300;font-size:14px;' . 'color:' . $palette['ink3'] . ';'; -// The card surface is built per-row out of avatar+content TDs (the -// outer table itself stays transparent). The timeline TD lives on the -// page background and carries a thick rail on its left edge. -$card_padding_y = 18; -$card_corner_radius = 8; +$card_padding_y = 18; +$card_corner_radius = 8; +$row_gap = 12; // vertical gap between consecutive cards -$avatar_cell_base = 'width:72px;vertical-align:middle;' - . 'padding:' . $card_padding_y . 'px 0 ' . $card_padding_y . 'px 18px;' +// Inner card table — full rounded surface containing the avatar + +// content cells. Each event row drops one of these into the outer +// section table's left column. +$card_outer_style = 'width:100%;' . 'background:' . $palette['surface'] . ';' - . 'border-left:1px solid ' . $palette['border'] . ';'; + . 'border:1px solid ' . $palette['border'] . ';' + . 'border-radius:' . $card_corner_radius . 'px;' + . 'box-shadow:0 1px 3px rgba(0,0,0,0.04);'; -$content_cell_base = 'vertical-align:middle;' - . 'padding:' . $card_padding_y . 'px 18px ' . $card_padding_y . 'px 16px;' - . 'background:' . $palette['surface'] . ';' - . 'border-right:1px solid ' . $palette['border'] . ';' +$avatar_inner_td = 'width:72px;vertical-align:middle;' + . 'padding:' . $card_padding_y . 'px 0 ' . $card_padding_y . 'px 18px;'; + +$content_inner_td = 'vertical-align:middle;' + . 'padding:' . $card_padding_y . 'px 18px;' . 'font-family:' . $font_stack . ';font-size:15px;line-height:1.4;' . 'font-weight:300;color:' . $palette['ink'] . ';'; -$timeline_cell_base = 'width:140px;vertical-align:middle;' - . 'padding:' . $card_padding_y . 'px 14px ' . $card_padding_y . 'px 24px;' +// Outer row cells: card on the left, a small gutter, then the rail. +$outer_card_td = 'vertical-align:middle;padding-bottom:' . $row_gap . 'px;'; +$outer_gutter_td = 'width:16px;padding-bottom:' . $row_gap . 'px;'; +$outer_rail_td = 'width:140px;vertical-align:middle;' + . 'padding:0 14px ' . $row_gap . 'px 24px;' . 'border-left:4px solid ' . $palette['rail'] . ';' - . 'background:' . $palette['bg'] . ';' . 'font-family:' . $font_stack . ';' . 'color:' . $palette['ink3'] . ';white-space:nowrap;'; -// A 16px wide gutter cell sits between the card and the timeline so -// the rail visibly separates from the card edge. -$gutter_cell_style = 'width:16px;background:' . $palette['bg'] . ';'; - // Renders one event row in the consistent 3-column layout shared by // every section (avatar | content | date on the timeline rail). $summary_kicker_style = 'margin:18px 0 8px;' @@ -431,10 +432,11 @@ $summary_item_style = 'padding:3px 0;'; // // $show_dot suppresses the dot on rows whose upcoming-day matches // the previous row, so each calendar day has exactly one dot. -// Every row is now a self-contained mini-card (full border on all -// sides, rounded corners). Vertical gaps between rows come from the -// outer table's border-spacing — the rail naturally breaks between -// rows along with the cards. +// Each event row builds a fully-rounded inner card (a nested table) +// and parks it in the outer row's left TD; the rail TD on the right +// carries the continuous timeline rail as a left-border. The outer +// table uses border-collapse:collapse so adjacent rail TDs merge +// their left-borders into ONE unbroken line across the row gaps. // // $show_dot suppresses the dot AND the day+month line on rows whose // upcoming-day matches the previous (only the year is then shown). @@ -446,22 +448,20 @@ $event_row = static function ( use ( $record_avatars, $date_parts, - $avatar_cell_base, - $content_cell_base, - $timeline_cell_base, - $gutter_cell_style, - $card_corner_radius, + $card_outer_style, + $avatar_inner_td, + $content_inner_td, + $outer_card_td, + $outer_gutter_td, + $outer_rail_td, $palette, ): string { - $avatar_extra = 'border-top:1px solid ' . $palette['border'] . ';' - . 'border-bottom:1px solid ' . $palette['border'] . ';' - . 'border-top-left-radius:' . $card_corner_radius . 'px;' - . 'border-bottom-left-radius:' . $card_corner_radius . 'px;'; - - $content_extra = 'border-top:1px solid ' . $palette['border'] . ';' - . 'border-bottom:1px solid ' . $palette['border'] . ';' - . 'border-top-right-radius:' . $card_corner_radius . 'px;' - . 'border-bottom-right-radius:' . $card_corner_radius . 'px;'; + $card_html = + '' + . '' + . '' + . '
' . $record_avatars($fact) . '' . $body_html . '
'; $parts = $date_parts($fact); @@ -472,9 +472,6 @@ $event_row = static function ( . 'box-shadow:0 0 0 4px ' . $palette['bg'] . ';">' : ''; - // When the dot is suppressed, also drop the day+month (it's - // the same as the row above) and show only the year — a touch - // larger than the always-visible year so it reads on its own. if ($show_dot) { $date_html = '' @@ -492,19 +489,32 @@ $event_row = static function ( } return '' - . '' . $record_avatars($fact) . '' - . '' . $body_html . '' - . '' - . '' . $dot_html . $date_html . '' + . '' . $card_html . '' + . '' + . '' . $dot_html . $date_html . '' . ''; }; -// Outer section table is transparent. border-spacing puts a 10px -// vertical gap between rows so each card stands on its own. +// Outer section table uses border-collapse:collapse so the rail +// border-lefts merge into a continuous line across all row gaps. $card_open = ''; + . 'style="width:100%;border-collapse:collapse;">'; $card_close = '
'; +// Downward-pointing CSS triangle, coloured to match the rail, used as +// the closing arrow that visually caps each section's timeline. +$timeline_close_row = '' + . '' + . '' + . '' + . '' + . ''; + ?> @@ -574,6 +584,7 @@ $card_close = ''; echo $event_row($fact, $body, $show_dot); ?> + @@ -623,6 +634,7 @@ $card_close = ''; echo $event_row($fact, $body, $show_dot); ?> + @@ -672,6 +684,7 @@ $card_close = ''; echo $event_row($fact, $body, $show_dot); ?> +