/* Archives web app: shared components on the Shop tokens (tokens.css). Every screen builds from these; a screen
   adds layout, not new paint. Preview: /account/?styleguide=1. */

/* Type helpers */
.label{font:500 var(--fs-label)/1.2 var(--label);letter-spacing:var(--track);text-transform:uppercase;color:var(--ink)}
.label-s{font-size:var(--fs-label-s)}
.label-l{font-size:var(--fs-label-l)}
.label.muted,.muted{color:var(--muted)}
.title{margin:0;font:400 var(--fs-title)/1.15 var(--serif);letter-spacing:-.01em;color:var(--ink);text-wrap:balance}
.title-l{font-size:var(--fs-title-l);line-height:1.1}
.display{margin:0;font:400 var(--fs-display)/1.02 var(--serif);letter-spacing:-.01em;text-wrap:balance}
.body{margin:0;font:var(--fs-body)/1.5 var(--sans);color:var(--ink)}
.body.muted{color:var(--muted)}

/* Hairline */
.rule{border:0;border-top:1px solid var(--line);margin:0;height:0}

/* Buttons: filled ink by default, outline hairline, or text. All at least 44 px. */
.btn{all:unset;box-sizing:border-box;cursor:pointer;-webkit-tap-highlight-color:transparent;display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);min-height:var(--tap);min-width:var(--tap);padding:0 var(--s4);border:1px solid var(--ink);border-radius:var(--r-control);background:var(--ink);color:var(--on-ink);font:500 var(--fs-label-l)/1 var(--label);letter-spacing:var(--track);text-transform:uppercase;text-align:center;white-space:nowrap;transition:transform var(--t-fast) var(--ease),background-color var(--t) var(--ease),color var(--t) var(--ease),border-color var(--t) var(--ease),opacity var(--t) var(--ease)}
/* account.css paints every button:hover #f3f4f6; a .btn keeps its own paint on hover (variants follow). */
.btn:hover{background:var(--ink)}
.btn:disabled,.btn[aria-disabled="true"]{opacity:.45;cursor:default;transform:none}
/* A filled button that can't be pressed yet reads as an empty slot, not a muddy half-transparent slab (Night, Nov 9). */
.btn:not(.btn-outline):not(.btn-text):not(.btn-on-photo):is(:disabled,[aria-disabled="true"]){opacity:1;background:var(--fill);color:var(--muted);border-color:var(--line)}
.btn:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.btn-outline{background:transparent;color:var(--ink);border-color:var(--line)}
.btn-outline:hover{border-color:var(--ink)}
.btn-text{background:transparent;color:var(--ink);border-color:transparent;padding:0 var(--s2);text-decoration:underline;text-underline-offset:4px}
.btn-danger{background:transparent;color:var(--danger);border-color:var(--danger)}
.btn-action{background:var(--action);color:var(--on-ink);border-color:var(--action)}
.btn-outline:hover,.btn-text:hover,.btn-danger:hover{background:transparent}
.btn-action:hover{background:var(--action)}
.btn-block{display:flex;width:100%}
.btn-on-photo{background:var(--bg);color:var(--ink);border-color:var(--bg)}
.btn-on-photo:focus-visible{outline-color:var(--on-photo)}
.btn-on-photo:hover{background:var(--bg)}

/* 6A: the floating pill tab bar, the only thing that floats. Equal-width segments under one sliding pill (.pill-ind,
   placed by shell.js through --tab, a number that follows a swipe between whole tabs). Hide with .is-off while selecting.
   Labels keep one colour; the pill carries an ink copy of the words (.pill-words) slid opposite to it, so the ink label
   is exactly the part under the pill on every frame. In the app (Nov 9) the bar holds Home, Archive and Inbox, and You
   is a round avatar button (.c-you) of the same height 8 px to its right; the pair is centred together (--you-shift). */
.btn-pill-bar{--you-w:calc(var(--tap) + 2 * var(--s1));--you-shift:0px;position:fixed;left:50%;bottom:calc(var(--s4) + env(safe-area-inset-bottom,0px));z-index:45;transform:translateX(calc(-50% + var(--you-shift)));display:grid;grid-auto-flow:column;grid-auto-columns:minmax(80px,1fr);align-items:center;gap:0;margin:0;padding:var(--s1);border-radius:var(--r-pill);background:var(--bar-bg);box-shadow:0 0 0 1px var(--bar-edge);transition:transform var(--t-slow) var(--ease),opacity var(--t-slow) var(--ease)}
.btn-pill-bar:has(>.c-you){--you-shift:calc((var(--you-w) + var(--s2)) / -2)}
.btn-pill-bar.is-off{transform:translate(calc(-50% + var(--you-shift)),calc(100% + 24px));opacity:0;pointer-events:none}
.btn-pill-bar>a,.btn-pill-bar>button{all:unset;box-sizing:border-box;cursor:pointer;-webkit-tap-highlight-color:transparent;position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:100%;min-height:var(--tap);min-width:var(--tap);padding:0 var(--s3);border-radius:var(--r-pill);font:500 var(--fs-label)/1 var(--label);letter-spacing:var(--track);text-transform:uppercase;color:var(--bar-text)}
.btn-pill-bar:not(:has(>.pill-ind))>:is(a,button)[aria-current="page"]{color:var(--bar-on-pill)}
.btn-pill-bar>:is(a,button):focus-visible{outline:2px solid var(--on-ink);outline-offset:-4px}
.btn-pill-bar .pill-ind{position:absolute;z-index:2;overflow:hidden;top:var(--s1);bottom:var(--s1);left:var(--s1);width:calc((100% - 2 * var(--s1)) / var(--tabs,3));border-radius:var(--r-pill);background:var(--bar-pill);translate:calc(var(--tab,0) * 100%) 0;opacity:var(--pill-o,1);transition:translate var(--t-spring) var(--spring),opacity var(--t-spring) var(--ease);pointer-events:none}
.btn-pill-bar:not(:has([aria-current="page"])) .pill-ind{opacity:0}
.btn-pill-bar .pill-words{position:absolute;top:0;bottom:0;left:0;display:grid;grid-auto-flow:column;grid-auto-columns:1fr;width:calc(var(--tabs,3) * 100%);translate:calc(var(--tab,0) * -100% / var(--tabs,3)) 0;transition:translate var(--t-spring) var(--spring);font:500 var(--fs-label)/1 var(--label);letter-spacing:var(--track);text-transform:uppercase;color:var(--bar-on-pill)}
.btn-pill-bar .pill-words>span{display:flex;align-items:center;justify-content:center;padding:0 var(--s3)}
.btn-pill-bar.is-dragging .pill-ind,.btn-pill-bar.is-dragging .pill-words,.btn-pill-bar.is-dragging>.c-you::after{transition:none}
/* You: the avatar in a round button the bar's height, outside the bar to its right; a pill-coloured ring lights while
   You is current (--you-on, which follows a swipe too). */
.btn-pill-bar>a.c-you{position:absolute;top:0;left:calc(100% + var(--s2));width:var(--you-w);height:var(--you-w);min-width:0;min-height:0;padding:0;border-radius:50%;background:var(--bar-bg);box-shadow:0 0 0 1px var(--bar-edge)}
.btn-pill-bar>a.c-you::after{content:"";position:absolute;inset:0;border-radius:50%;box-shadow:inset 0 0 0 2px var(--bar-pill);opacity:var(--you-on,0);transition:opacity var(--t-spring) var(--ease);pointer-events:none}
.c-you-face{display:grid;place-items:center;width:calc(var(--you-w) - 2 * var(--s2));aspect-ratio:1;border-radius:50%;overflow:hidden;background:var(--bar-pill);color:var(--bar-on-pill);font:600 15px/1 var(--sans);letter-spacing:0;text-transform:none}
.c-you-face img{width:100%;height:100%;object-fit:cover;display:block}
.c-you-label{display:none}
.btn-pill-bar>a.c-you .badge{top:2px;right:2px}
.btn-pill-bar>a.c-you:focus-visible{outline-offset:2px}
.btn-pill-bar .badge{position:absolute;top:8px;right:calc(50% - 30px);width:8px;height:8px;border-radius:50%;background:var(--on-ink);box-shadow:0 0 0 2px var(--ink);transition:scale var(--t-release) var(--spring-bounce),background-color var(--t) var(--ease)}
.btn-pill-bar:not(:has(>.pill-ind))>[aria-current="page"] .badge{background:var(--ink);box-shadow:0 0 0 2px var(--bg)}
@starting-style{.btn-pill-bar .badge{scale:0}}
.under-bar{padding-bottom:calc(var(--bar-h) + var(--s6) + env(safe-area-inset-bottom,0px))}

/* Sheet: --surface (white by day), 12 px top radius, a hairline, from the bottom on phones and centred on laptops. Works as <dialog> or <div>. */
.sheet{box-sizing:border-box;position:fixed;inset:auto 0 0 0;width:100%;max-width:none;max-height:92svh;margin:0;padding:var(--s2) var(--gutter) calc(var(--s5) + env(safe-area-inset-bottom,0px));border:1px solid var(--line);border-bottom:0;border-radius:var(--r-sheet) var(--r-sheet) 0 0;background:var(--surface);color:var(--ink);overflow:auto;overscroll-behavior:contain;z-index:50}
.sheet::backdrop{background:var(--scrim)}
.sheet:focus{outline:none}
.sheet::before{content:'';display:block;width:36px;height:4px;margin:var(--s1) auto var(--s2);border-radius:2px;background:var(--line)}
.sheet-head{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--s3);min-height:var(--tap)}
.sheet-head .title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sheet-close{all:unset;box-sizing:border-box;cursor:pointer;-webkit-tap-highlight-color:transparent;display:inline-flex;align-items:center;justify-content:center;width:var(--tap);height:var(--tap);margin-right:calc(-1 * var(--s2));border-radius:var(--r-control);color:var(--ink);font:500 var(--fs-label)/1 var(--label);letter-spacing:var(--track);text-transform:uppercase;transition:background-color var(--t) var(--ease),transform var(--t-fast) var(--ease)}
.sheet-close:hover{background:var(--fill)}
.sheet-close:focus-visible{outline:2px solid var(--ink);outline-offset:-2px}
.sheet-body{display:grid;gap:var(--s4);padding-top:var(--s3)}
.sheet-actions{display:flex;gap:var(--s2);padding-top:var(--s2)}
.sheet-actions .btn{flex:1}
@media (min-width:761px){
 .sheet{inset:50% auto auto 50%;transform:translate(-50%,-50%);width:min(480px,calc(100% - 2*var(--gutter)));max-height:86vh;padding:var(--s4) var(--s5) var(--s5);border-bottom:1px solid var(--line);border-radius:var(--r-sheet)}
 .sheet::before{display:none}
}
/* 8B laptops (1024 px and up): a sheet is a full-height panel on the right, the page still visible beside it. */
@media (min-width:1024px){
 .sheet{inset:0 0 0 auto;transform:none;width:min(440px,100%);height:100%;max-height:none;padding:var(--s5);border:0;border-left:1px solid var(--line);border-radius:0}
}

/* Inputs: 8 px, hairline, 16 px so phones do not zoom. */
.input{box-sizing:border-box;display:block;width:100%;min-height:48px;margin:0;padding:10px var(--s3);border:1px solid var(--line);border-radius:var(--r-control);background:var(--bg);color:var(--ink);font:16px/1.3 var(--sans);transition:border-color var(--t) var(--ease)}
.input::placeholder{color:var(--muted)}
.input:hover{border-color:var(--line-strong)}
.input:focus-visible{outline:2px solid var(--ink);outline-offset:2px;border-color:var(--ink)}
.input[aria-invalid="true"]{border-color:var(--danger)}
textarea.input{min-height:96px;resize:vertical}
.field{display:grid;gap:var(--s2)}
.field>.label{color:var(--muted)}
.note{margin:0;font:var(--fs-label)/1.45 var(--sans);color:var(--muted)}
.note a{color:inherit;display:inline-block;padding:14px 0;margin:-14px 0;text-decoration:underline;text-underline-offset:3px}
.error{margin:0;font:var(--fs-label-l)/1.4 var(--sans);color:var(--danger)}

/* Print (4A): a square photo, then the margin row: place and people on the left, the date on the right. */
.print{display:grid;gap:0;margin:0;background:var(--bg);color:var(--ink)}
.print-photo{position:relative;display:block;aspect-ratio:1;overflow:hidden;border-radius:var(--r-photo);background:var(--fill);outline:var(--print-edge) solid var(--print-edge-color);outline-offset:calc(-1 * var(--print-edge))}
/* Night: a thin light edge round the print (--print-edge), drawn over the photo's outer pixels, never a tint. */
.print-photo img{display:block;width:100%;height:100%;object-fit:cover}
.print-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3);min-height:32px;padding:var(--s2) 0 var(--s3)}
.print-meta{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:500 var(--fs-label-s)/1.2 var(--label);letter-spacing:var(--track);text-transform:uppercase;color:var(--ink)}
.print-meta .print-who{color:var(--muted)}
.print-date{flex:none;font:500 var(--fs-label-s)/1.2 var(--label);letter-spacing:var(--track);text-transform:uppercase;color:var(--muted);font-variant-numeric:tabular-nums}
.print .title{padding:0 0 var(--s2)}
.print-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s4) var(--s3)}
@media (min-width:761px){.print-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--s5) var(--s4)}}

/* Photo tiles (contact sheets): square, no radius, decode then fade. */
.photo{position:relative;display:block;aspect-ratio:1;overflow:hidden;border-radius:var(--r-photo);background:var(--fill)}
.photo img{display:block;width:100%;height:100%;object-fit:cover}
.img{opacity:0;transition:opacity var(--t-slow) var(--ease)}
.img.ready{opacity:1}
.scrim-top::before,.scrim-bottom::after{content:'';position:absolute;left:0;right:0;pointer-events:none;z-index:1}
.scrim-top::before{top:0;height:45%;background:var(--scrim-photo-top)}
.scrim-bottom::after{bottom:0;height:50%;background:var(--scrim-photo-bottom)}
.on-photo{position:relative;z-index:2;color:var(--on-photo);text-shadow:var(--photo-text-shadow)}

/* Chips: hairline, 8 px, filled when on. Chips are buttons, so they keep the 44 px height. */
.chip{all:unset;box-sizing:border-box;cursor:pointer;-webkit-tap-highlight-color:transparent;display:inline-flex;align-items:center;gap:var(--s2);min-height:var(--tap);padding:0 var(--s4);border:1px solid var(--line);border-radius:var(--r-control);background:var(--bg);color:var(--ink);font:500 var(--fs-label)/1 var(--label);letter-spacing:var(--track);text-transform:uppercase;white-space:nowrap;transition:background-color var(--t) var(--ease),border-color var(--t) var(--ease),color var(--t) var(--ease),transform var(--t-fast) var(--ease)}
.chip:hover{border-color:var(--ink);background:var(--bg)}
.chip[aria-pressed="true"],.chip.is-on,.chip[aria-pressed="true"]:hover,.chip.is-on:hover{background:var(--ink);border-color:var(--ink);color:var(--on-ink)}
.chip:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.chip-row{display:flex;flex-wrap:wrap;gap:var(--s2)}
.chip-row.scroll{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;margin:0 calc(-1 * var(--gutter));padding:0 var(--gutter)}
.chip-row.scroll::-webkit-scrollbar{display:none}

/* Avatar: a disc with the initial in the label face, or the photo. 40 px by default; wrap in a 44 px target. */
.avatar{box-sizing:border-box;flex:none;display:inline-grid;place-items:center;width:40px;height:40px;border-radius:50%;overflow:hidden;background:var(--fill);color:var(--ink);font:500 var(--fs-label-l)/1 var(--label);letter-spacing:0;text-transform:uppercase}
.avatar img{display:block;width:100%;height:100%;object-fit:cover}
.avatar-sm{width:28px;height:28px;font-size:var(--fs-label-s)}
.avatar-lg{width:96px;height:96px;font-size:32px}
.avatar-btn{all:unset;box-sizing:border-box;cursor:pointer;-webkit-tap-highlight-color:transparent;display:inline-grid;place-items:center;min-width:var(--tap);min-height:var(--tap);border-radius:50%}
.avatar-btn:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

/* Toast (Nov 8): a compact ink pill above the tab bar that springs up, an optional 32 px avatar or photo on the
   left, one line (two at most) in the system sans, an optional action on the right. toast.js: replaces rather than
   piles up, 2.5 s, swipe down to dismiss, role="status". Reduced motion: a fade. */
.toast{position:fixed;left:50%;bottom:calc(var(--bar-h) + var(--s5) + env(safe-area-inset-bottom,0px));z-index:46;transform:translateX(-50%);box-sizing:border-box;display:flex;align-items:center;gap:var(--s3);width:max-content;max-width:min(440px,calc(100% - 2 * var(--gutter)));min-height:48px;margin:0;padding:var(--s2) var(--s5);border-radius:var(--r-pill);background:var(--toast-bg);color:var(--toast-ink);font:500 14px/1.3 var(--sans);text-align:left;touch-action:none;user-select:none;-webkit-user-select:none;transition:translate var(--t-spring) var(--spring),opacity var(--t) var(--ease),bottom var(--t-slow) var(--ease)}
.toast[hidden]{display:none}
@starting-style{.toast{translate:0 calc(100% + var(--s5));opacity:0}}
.toast.is-leaving{translate:0 calc(100% + var(--s5));opacity:0;transition:translate var(--t) var(--ease),opacity var(--t) var(--ease)}
.toast.has-thumb{padding-left:var(--s2)}
.toast.has-action{padding-right:var(--s1)}
.toast-text{min-width:0;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}
.toast-thumb{flex:none;width:32px;height:32px;border-radius:6px;object-fit:cover;background:var(--toast-hover)}
.toast-thumb.is-round{border-radius:50%}
.toast-action{all:unset;box-sizing:border-box;flex:none;cursor:pointer;-webkit-tap-highlight-color:transparent;display:inline-flex;align-items:center;min-height:var(--tap);padding:0 var(--s4);border-radius:var(--r-pill);font:500 var(--fs-label)/1 var(--label);letter-spacing:var(--track);text-transform:uppercase;color:var(--on-ink);transition:background-color var(--t) var(--ease)}
.toast-action:focus-visible{outline:2px solid var(--on-ink);outline-offset:-4px}
@media (hover:hover){.toast-action:hover{background:var(--toast-hover)}}
/* No tab bar under it (laptops, select mode, a chat): it sits lower. */
.toast.no-bar,body.c-tabs-off .toast{bottom:calc(var(--s5) + env(safe-area-inset-bottom,0px))}

/* Empty state: a title, one line, one action. (.empty-state, not .empty: compose.js and the legacy archive already use .empty.) */
.empty-state{display:grid;justify-items:center;gap:var(--s3);padding:var(--s8) var(--gutter);text-align:center;color:var(--ink)}
.empty-state .title{margin:0}
.empty-state .body{color:var(--muted);max-width:32ch}
.empty-state .btn{margin-top:var(--s2)}

/* Loading: shimmer while data is on its way (AGENTS.md), 1.5 s left to right. */
.skeleton{background:linear-gradient(90deg,var(--shimmer-a) 0%,var(--shimmer-b) 50%,var(--shimmer-a) 100%) 0 0/200% 100%;animation:shimmer var(--shimmer) linear infinite;border-radius:var(--r-control)}
.skeleton.photo,.skeleton.print-photo{border-radius:var(--r-photo)}
@keyframes shimmer{from{background-position:100% 0}to{background-position:-100% 0}}

/* 7A: a print develops once per device, 1.8 s, tiles 220 ms apart (set --i on each tile from script with
   el.style.setProperty("--i",n): inline style attributes are blocked by the CSP). Screens add .develop
   on the first visit only and html.developed afterwards (a localStorage flag). */
.develop{animation:develop var(--develop) var(--ease) both;animation-delay:calc(var(--i,0) * var(--develop-stagger))}
@keyframes develop{0%{opacity:.15;filter:saturate(0) contrast(.55) brightness(1.5)}55%{opacity:1;filter:saturate(.35) contrast(.8) brightness(1.15)}100%{opacity:1;filter:none}}
html.developed .develop{animation:none}

/* Lists: a hairline between rows, 44 px rows. */
.list{display:grid;margin:0;padding:0;list-style:none}
.list>*{display:flex;align-items:center;gap:var(--s3);min-height:56px;padding:var(--s2) 0;border-bottom:1px solid var(--line)}
.list>*:last-child{border-bottom:0}
.list .grow{flex:1;min-width:0}

/* Motion (Nov 8, "satisfying features"): presses, sheets, page transitions. Tokens: --spring, --spring-bounce,
   --t-spring, --t-press, --t-release, --press (tokens.css). Research and reasons: docs/WEB-THEME.md → Motion. */

/* Presses: shell.js scales any .pressable (and .btn, .chip, .sheet-close, tab-bar and header buttons, .list rows that
   are buttons) to --press on pointerdown and springs it back on release, with the `scale` property so it composes
   with a screen's own transform. Screens opt other elements in with class="pressable". No tap flash anywhere. */
.pressable{-webkit-tap-highlight-color:transparent;touch-action:manipulation;cursor:pointer}
.pressable:focus{outline:none}
.pressable:focus-visible{outline:2px solid var(--ink);outline-offset:3px}

/* Sheets rise on a spring and their backdrop fades (enter everywhere with @starting-style, exit where
   overlay/allow-discrete is supported). From 761 px a sheet settles from just below, from 1024 px it slides in from
   the right. A sheet opened from a tile zooms from that tile instead (shell.js). Sheets with their own keyframes
   (.fe-sheet) keep them until their owner moves to this. */
dialog.sheet:not(.fe-sheet){transition:translate var(--t-spring) var(--spring),opacity var(--t) var(--ease),overlay var(--t-spring) allow-discrete,display var(--t-spring) allow-discrete}
dialog.sheet:not(.fe-sheet):not([open]){translate:0 100%}
@starting-style{dialog.sheet:not(.fe-sheet)[open]{translate:0 100%}}
dialog.sheet::backdrop{opacity:1;transition:opacity var(--t-slow) var(--ease),overlay var(--t-slow) allow-discrete,display var(--t-slow) allow-discrete}
dialog.sheet:not([open])::backdrop{opacity:0}
@starting-style{dialog.sheet[open]::backdrop{opacity:0}}
@media (min-width:761px){
 dialog.sheet:not(.fe-sheet):not([open]){translate:0 24px;opacity:0}
 @starting-style{dialog.sheet:not(.fe-sheet)[open]{translate:0 24px;opacity:0}}
}
@media (min-width:1024px){
 dialog.sheet:not(.fe-sheet):not([open]){translate:100% 0;opacity:1}
 @starting-style{dialog.sheet:not(.fe-sheet)[open]{translate:100% 0;opacity:1}}
}
/* Zooming from a tile (shell.js animates it): no rise underneath. */
dialog.sheet.c-zoom[open]{translate:none;transition:none}

/* Page transitions (View Transitions API, same-document; Safari 18+, Chrome 111+), round-2 board 4B zoom-through:
   html[data-vt=grow] grows the new page out of what was tapped (--vt-ox/--vt-oy, its centre; --vt-s, its width as a
   share of the screen) while the old one recedes; html[data-vt=shrink] (going back) shrinks the old page into the
   place it came from; fade otherwise. shell.js sets all four. The header and the tab bar hold still; the tab pill
   glides on the spring. Without the API: a 200 ms crossfade (.c-enter). Reduced motion: crossfades only. */
.c-shell header{view-transition-name:shell-header}
#app-nav.btn-pill-bar{view-transition-name:tab-bar}
::view-transition-group(*){animation-duration:var(--t-spring);animation-timing-function:var(--spring)}
html[data-vt=grow]::view-transition-new(root),html[data-vt=shrink]::view-transition-old(root){transform-origin:var(--vt-ox,50%) var(--vt-oy,50%);animation-duration:var(--t-spring);animation-timing-function:var(--spring);animation-fill-mode:both}
html[data-vt=grow]::view-transition-new(root){animation-name:vt-grow}
html[data-vt=grow]::view-transition-old(root){animation:vt-recede var(--t-spring) var(--ease) both}
html[data-vt=shrink]::view-transition-old(root){z-index:1;animation-name:vt-shrink;animation-timing-function:var(--ease)}
html[data-vt=shrink]::view-transition-new(root){animation:vt-return var(--t-spring) var(--ease) both}
html[data-vt=fade]::view-transition-old(root),html[data-vt=fade]::view-transition-new(root){animation-duration:var(--t);animation-timing-function:var(--ease)}
/* The tab bar is never snapshotted: its old image is dropped and the new one is live, so the pill glides on its own
   transition from the frame of the tap, under labels that hold their colour (Nov 9). */
html[data-vt]::view-transition-group(tab-bar),html[data-vt]::view-transition-new(tab-bar){animation:none}
html[data-vt]::view-transition-old(tab-bar){display:none}
@keyframes vt-grow{from{scale:var(--vt-s,.3);opacity:0}35%{opacity:1}}
@keyframes vt-shrink{65%{opacity:1}to{scale:var(--vt-s,.3);opacity:0}}
@keyframes vt-recede{to{scale:.96;opacity:0}}
@keyframes vt-return{from{scale:.96;opacity:0}}
.c-enter{animation:c-enter var(--t) var(--ease)}
@keyframes c-enter{from{opacity:0}}

@media (prefers-reduced-motion:reduce){
 .btn,.btn-pill-bar,.btn-pill-bar>a,.btn-pill-bar>button,.sheet-close,.input,.chip,.img{transition:none}
 .toast,.toast.is-leaving{translate:none;transition:opacity var(--t) var(--ease)}
 @starting-style{.toast{translate:none;opacity:0}}
 .btn-pill-bar.is-off{transform:translateX(-50%)}
 .btn-pill-bar .pill-ind{transition:none}
 .skeleton{animation:none;background:var(--shimmer-a)}
 .develop{animation:none}
 /* Sheets and pages crossfade only. */
 dialog.sheet:not(.fe-sheet),dialog.sheet:not(.fe-sheet):not([open]){translate:none;transition:opacity var(--t) var(--ease),overlay var(--t) allow-discrete,display var(--t) allow-discrete}
 dialog.sheet:not(.fe-sheet):not([open]){opacity:0}
 @starting-style{dialog.sheet:not(.fe-sheet)[open]{translate:none;opacity:0}}
 ::view-transition-group(*){animation-duration:var(--t);animation-timing-function:var(--ease)}
}

/* Tab to tab (Nov 9): the page slides sideways in the tab's direction; the header and the bar stay put. */
html[data-vt=slide-next]::view-transition-old(root){animation:vt-out-left var(--t-spring) var(--spring) both}
html[data-vt=slide-next]::view-transition-new(root){animation:vt-in-right var(--t-spring) var(--spring) both}
html[data-vt=slide-prev]::view-transition-old(root){animation:vt-out-right var(--t-spring) var(--spring) both}
html[data-vt=slide-prev]::view-transition-new(root){animation:vt-in-left var(--t-spring) var(--spring) both}
@keyframes vt-out-left{to{translate:-100% 0}}
@keyframes vt-in-right{from{translate:100% 0}}
@keyframes vt-out-right{to{translate:100% 0}}
@keyframes vt-in-left{from{translate:-100% 0}}
html[data-vt^=slide]::view-transition-group(shell-header){animation:none}

/* One close button everywhere (Nov 9): a 44px target with a drawn 20px ×, centred, the same on every sheet and page.
   The text glyph inside stays for screen readers but is not painted; .is-text keeps a worded button ("Back") as text. */
:is(.sheet-close,.pv-close,.scan-close):not(.is-text,.h-close,.fe-back,:has(svg,.pc-x,img)){width:var(--tap);height:var(--tap);min-width:var(--tap);display:inline-flex;align-items:center;justify-content:center;font-size:0;line-height:0;color:var(--ink);position:relative;flex:none}
:is(.sheet-close,.pv-close,.scan-close):not(.is-text,.h-close,.fe-back,:has(svg,.pc-x,img))::before{content:"";width:20px;height:20px;background:currentColor;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M4 4l12 12M16 4L4 16' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center/20px 20px no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M4 4l12 12M16 4L4 16' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center/20px 20px no-repeat}
.on-photo :is(.pv-close),.pv-close{color:#fff}
:is(.sheet-close,.pv-close,.scan-close):focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:var(--r-control)}
