/* ============================================================
   bruteposting.app — design system
   Tokens and components transcribed from Figma (channel gme4q74h).
   Every view lives in index.html.
   ============================================================ */

@font-face {
  font-family: 'Induction';
  src: url('./Induction.woff') format('woff');
  font-weight: 400;
  /* block, not swap: the wordmark is 28px, so a swap is a very visible
     reflow. A short invisible period then the real face is better. */
  font-display: block;
}

:root {
  /* Figma colour styles */
  --primary:       #FF5C00;   /* Primary/Mid   */
  --panel-bg: #FF5C00;
  --primary-light: #FF7A2E;   /* Primary/Light */
  --primary-dark:  #D65904;   /* Primary/Dark  */
  --g01: #FFFFFF;             /* Gray/01  post body, display name */
  --g02: #D9D9D9;             /* Gray/02  badge label */
  --g03: #777777;             /* Gray/003 handle, date, footer */
  --g04: #3C3836;             /* Gray/004 every 1px border */
  --g09: #000000;             /* Gray/009 page bg, text on orange */
  --surface: #0B0B0B;         /* post card */

  --flame-wm: url("data:image/svg+xml,%3Csvg%20fill-opacity%3D%220.12%22%20width%3D%22100%22%20height%3D%22119%22%20viewBox%3D%220%200%20100%20119%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%3Cpath%20d%3D%22M1.57115%2084.5893C5.17115%20104.189%2023.0711%20115.089%2031.5711%20118.089C29.2378%20115.756%2024.471%20108.889%2024.071%20100.089C23.671%2091.2894%2029.2377%2086.0893%2032.071%2084.5893C30.5711%2092.5893%2031.5711%20101.489%2038.571%20100.089C45%2098.8036%2043.571%2093.5894%2040.071%2078.0894C37.271%2065.6894%2047.571%2056.9227%2053.071%2054.0894C52.571%2065.5894%2053.071%2074.0894%2067.071%2086.0894C78.271%2095.6894%2073.071%20110.761%2069.071%20117.096C82.6401%20110.894%2095.5553%20100.936%2098.571%2086.0894C103.771%2060.4894%2093.4044%2046.4227%2087.571%2042.5893C88.2377%2047.9227%2087.071%2058.2894%2077.071%2057.0894C60.071%2054.5894%2079.571%2032.0893%2073.571%2018.5893C67.571%202.18933%2053.7377%20-0.577333%2047.571%200.0893335C55.071%205.08933%2060.571%2031.0893%2046.071%2032.0893C34.471%2032.8893%2034.571%2021.4227%2036.071%2015.5893C21.571%2020.5893%2023.571%2033.5893%2025.071%2037.5893C26.571%2041.5893%2032.071%2053.0894%2019.571%2055.5893C9.76516%2057.5505%208.57108%2048.0893%209.07115%2042.5893C3.07115%2050.5893%20-2.92885%2060.0893%201.57115%2084.5893Z%22%20fill%3D%22black%22%2F%3E%20%3C%2Fsvg%3E");   /* faint flame behind the orange surfaces */
  --fade-h: 130px;      /* the wash over the top of the feed */
  --radius: 0;          /* nothing on this site is rounded; the avatar is the one circle */
  --notch: 34px;
  --panel-pad: 32px;
  --page-pad: 16px;              /* 45° corner cut on orange panels */

  --f-display: 'Induction', 'Arial Black', sans-serif;
  --f-body:    'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --f-post:    'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --f-name:    'Instrument Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  --f-meta:    'Atkinson Hyperlegible Mono', ui-monospace, Menlo, monospace;
  --f-ui:      'Intel One Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }

html, body { height: 100%; }
/* held back until the first render so the empty shell never shows; the inline
   failsafe in the head reveals it even if the boot script never runs */
body { opacity: 0; }
body.ready { opacity: 1; }
/* ============================================================
   flash-in — a CRT striking, not a fade

   Everything steps. No interpolated opacity anywhere: each keyframe holds
   until the next one replaces it, so the eye reads discrete states rather
   than a ramp. Two blinks, an overshoot, then it settles.

   Blocks add a banded wipe on top, revealed in hard rows like a terminal
   painting itself line by line.
   ============================================================ */
@keyframes flash-in {
  0%   { opacity: 0; }
  18%  { opacity: 1; }
  30%  { opacity: 0; }
  44%  { opacity: 1; }
  56%  { opacity: .25; }
  70%  { opacity: 1; }
  84%  { opacity: .6; }
  100% { opacity: 1; }
}
@keyframes flash-wipe {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes flash-out {
  0%   { opacity: 1; }
  25%  { opacity: .15; }
  40%  { opacity: .7; }
  100% { opacity: 0; }
}

/* the block reveal: wipe and flicker together */
.rise-in {
  animation: flash-wipe .2s steps(6, end) both, flash-in .34s steps(1, end) both;
}
/* An element that owns a clip-path cannot also be wiped by one — the wipe
   replaces its notch for the whole reveal, so the corner cut only appeared
   once the animation ended. It keeps the flicker and skips the wipe. */
.panel.rise-in { animation: flash-in .34s steps(1, end) both; }
body {
  background: var(--g09);
  color: var(--g01);
  font: 400 14px/1.4 var(--f-ui);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  padding: var(--page-pad);
  display: flex; flex-direction: column;
}
.nav-shell { flex: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }
a { color: inherit; text-decoration: none; }
.credit a, .crumb a { text-decoration: underline; }
::selection { background: var(--primary); color: var(--g09); }

/* ---------- orange scrollbar, used everywhere ---------- */
/* Chromium drops the ::-webkit- rules entirely once scrollbar-width or
   scrollbar-color is set on an element, and renders its own rounded thumb
   instead. The standard properties are therefore scoped to engines with no
   ::-webkit- support at all, which is Firefox. */
@supports not selector(::-webkit-scrollbar) {
  * { scrollbar-width: thin; scrollbar-color: var(--primary) transparent; }
  .on-orange, .on-orange * { scrollbar-color: var(--g09) transparent; }
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--primary); border: 2px solid transparent;
  background-clip: content-box; border-radius: 0;
}
*::-webkit-scrollbar-thumb:hover { background: var(--primary-light); background-clip: content-box; }
/* on an orange surface the thumb must invert to stay visible */
.on-orange::-webkit-scrollbar-thumb,
.on-orange *::-webkit-scrollbar-thumb { background: var(--g09); background-clip: content-box; }

/* ============================================================
   nav
   ============================================================ */
.nav {
  display: flex; align-items: center; gap: 20px;
  padding: 12px 16px; background: var(--g09);
  position: relative; z-index: 40; flex: none;
}
/* the mark runs the full height of the wordmark and its subheading, which are
   stacked together in their own block beside it */
.brand { text-decoration: none; display: flex; align-items: stretch; gap: 10px; flex: none; }
.brand-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* A flex item will not resolve a ratio-derived width from a stretched height,
   so the height is stated and the width follows the artwork's 100:119. It is
   set beside the type that determines it at each step. */
.brand { --mark-h: 50px; }
.brand-mark {
  flex: none; display: block; color: var(--primary);
  height: var(--mark-h); width: calc(var(--mark-h) * 100 / 119);
}
.brand-mark svg { width: 100%; height: 100%; display: block; }
.brand-word {
  font: 400 28px/29px var(--f-display);
  color: var(--primary);
  letter-spacing: .01em;
}
.brand-tag { font: 400 14px/19.32px var(--f-ui); color: var(--g03); }

.nav-spacer { flex: 1; }
/* the right half of the nav strikes as one block, a beat after the brand */
.nav-right { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1; justify-content: flex-end; }

.modes { display: flex; flex: none; }
/* the pair reads as one control, so the shared edge is a single rule */
.modes .mode + .mode { margin-left: -1px; }
.modes .mode[aria-pressed='true'] { position: relative; z-index: 1; }
.mode {
  display: inline-flex; align-items: center; gap: 8px;
  height: 34px; padding: 0 16px; border: 1px solid var(--g04); background: var(--g09);
  font: 400 16px/22.08px var(--f-ui); color: var(--g02);
  display: inline-flex; align-items: center;
}
.mode:hover { border-color: var(--primary); }
.mode[aria-pressed='true'] { background: var(--primary); border-color: var(--primary); color: var(--g09); }

.hamburger { display: none; }

/* ============================================================
   input field — Figma set: Type x Theme x State
   .field     = Theme:Dark    .field.alt = Theme:Accent
   ============================================================ */
.field {
  display: flex; align-items: center; gap: 8px;
  height: 34px; padding: 0 8px 0 10px;
  background: var(--g09); border: 1px solid var(--g04);
  color: var(--g01); position: relative;
}
.field .ico { color: var(--g03); flex: none; display: flex; }
.field input { min-width: 0;
  flex: 1; min-width: 0; background: none; border: none; outline: none;
  font: 400 16px/22.08px var(--f-ui); color: var(--g01);
}
.field input::placeholder { color: var(--g04); }
.field .kbd {
  flex: none; display: grid; place-items: center;
  width: 20px; height: 21px; border: 1px solid var(--g04);
  font: 400 14px/19.32px var(--f-ui); color: var(--g04);
}
/* Focus strikes before it settles: the border blows white twice and lands on
   the colour the field would have taken anyway. Each keyframe states its own
   colour — a gap between two white steps would interpolate white and stay
   lit. No fill, so the resting rule owns the border once it has played. */
@keyframes border-strike {
  0%   { border-color: var(--g01); }
  22%  { border-color: var(--primary); }
  44%  { border-color: var(--g01); }
  100% { border-color: var(--primary); }
}
/* on an orange surface the field settles on black, so it strikes back to that */
@keyframes border-strike-alt {
  0%   { border-color: var(--g01); }
  22%  { border-color: var(--g09); }
  44%  { border-color: var(--g01); }
  100% { border-color: var(--g09); }
}
.field:focus-within {
  border-color: var(--primary);
  animation: border-strike .2s steps(1, end);
}

/* Theme=Accent */
.field.alt { background: var(--primary); border-color: var(--g09); color: var(--g09); }
.field.alt:focus-within {
  background: var(--primary-light); border-color: var(--g09);
  animation: border-strike-alt .2s steps(1, end);
}
.field.alt .ico { color: var(--g09); }
.field.alt input { color: var(--g09); }
.field.alt input::placeholder { color: var(--g04); }
.field.alt .kbd { color: var(--g04); border-color: var(--g04); }

/* Type=Dropdown */
.select-topic { cursor: pointer; }
.select-topic[aria-expanded="true"] .plus { transform: rotate(180deg); }
.select-topic .plus { transition: transform .18s ease; }

/* anchored to its control, styled like the aside cards it sits beside */
.dd { position: relative; }
.dd-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 40;
  min-width: 320px; max-width: 460px; max-height: 340px; overflow-y: auto;
  padding: 14px; display: flex; flex-direction: column; gap: 12px;
  background: var(--primary-light); border: 1px solid var(--g09);
}
.dd-clear { align-self: flex-start; }
.dd-clear .x { display: flex; width: 9px; height: 9px; }
.dd-clear .x svg { width: 100%; height: 100%; }
.select-topic .chips-inline { display: flex; gap: 4px; flex: 1; min-width: 0; overflow: hidden; }
.select-topic .ph { color: var(--g04); font: 400 16px/22.08px var(--f-ui); }
.plus {
  flex: none; display: flex; width: 16px; height: 16px; color: var(--g04);
}
.plus svg { width: 100%; height: 100%; }

/* ============================================================
   badge (topic chip)
   Transcribed from the Figma component set: State x Selected x Theme.
   .badge      = Theme:Dark   (sits on a black surface)
   .badge.alt  = Theme:Accent (sits on an orange surface)
   ============================================================ */
.badge {
  display: inline-flex; align-items: center; gap: 6px; text-transform: capitalize;
  padding: 3px 7px; font: 400 12px/16.56px var(--f-ui);
  cursor: pointer; white-space: nowrap;
}
.badge .n { font-variant-numeric: tabular-nums; }
.badge.sm { padding: 1px 5px; font-size: 10px; line-height: 13.8px; }

/* Theme=Dark */
.badge            { background: var(--g09); border: 1px solid var(--g04); color: var(--g02); }
.badge .n         { color: var(--g03); }
.badge:hover      { background: var(--g04); border-color: var(--g04); }
.badge.on         { background: var(--primary); border-color: var(--primary); color: var(--g09); }
.badge.on .n      { color: var(--g04); }
.badge.on:hover   { background: var(--primary-light); border-color: var(--primary); }

/* Theme=Accent */
.badge.alt          { background: var(--primary); border-color: var(--g09); color: var(--g09); }
.badge.alt .n       { color: var(--g04); }
.badge.alt:hover    { background: var(--primary-light); border-color: var(--g09); }
.badge.alt.on       { background: var(--g09); border-color: var(--g09); color: var(--g02); }
.badge.alt.on .n    { color: var(--g03); }
.badge.alt.on:hover { background: var(--g04); border-color: var(--g09); }

/* ============================================================
   button
   ============================================================ */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 8px; border: 1px solid transparent;
  font: 400 12px/16.56px var(--f-ui); color: var(--g03);
}
.btn:hover { color: var(--g01); }
.btn .i { display: flex; flex: none; }
.btn svg { width: 12px; height: 12px; flex: none; }
.btn.md svg { width: 14px; height: 14px; }
.btn.outline { border-color: var(--g04); }
.btn.outline:hover { border-color: var(--primary); color: var(--g01); }
.btn.solid { background: var(--primary); border-color: var(--primary); color: var(--g09); }
.btn.solid:hover { background: var(--primary-light); border-color: var(--primary-light); }
.btn.dark { background: var(--g09); border-color: var(--g09); color: var(--g01); }
.btn.md { padding: 7px 14px; font-size: 14px; }
.btn[disabled] { opacity: .45; pointer-events: none; }
/* on the orange panel */
.btn.alt { color: var(--g09); border-color: var(--g09); }
.btn.alt:hover { background: var(--g09); color: var(--primary); }

/* ============================================================
   checkbox — Figma component set: Checked x Theme
   .check     = Theme:Dark   (black surface)
   .check.alt = Theme:Accent (orange surface)
   ============================================================ */
.check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check .box {
  width: 16px; height: 16px; flex: none;
  border: 1px solid var(--primary); background: transparent;
  display: grid; place-items: center;
}
.check .box svg { opacity: 0; width: 12px; height: 12px; }
.check input:checked + .box svg { opacity: 1; }
.check .lbl { font: 400 12px/16.56px var(--f-ui); }
/* Ticking one is a filter going on, so the box blows out like every other
   committed state. The overlay reaches a pixel past the box to take the
   border with it — a white square with an orange outline reads as a bug. */
.check .box.struck::after { inset: -1px; }

/* Theme=Dark */
.check .lbl                     { color: var(--g01); }
.check .box                     { border-color: var(--primary); background: transparent; }
.check input:checked + .box     { background: var(--primary); border-color: var(--primary); }
.check .box svg                 { color: var(--g09); }

/* Theme=Accent */
.check.alt .lbl                 { color: var(--g09); }
.check.alt .box                 { border-color: var(--g09); background: var(--primary-light); }
.check.alt input:checked + .box { background: var(--g09); border-color: var(--g09); }
.check.alt .box svg             { color: var(--g01); }

/* ============================================================
   post card
   ============================================================ */
.post {
  background: var(--surface); border: 1px solid var(--g04); border-radius: var(--radius);
  display: flex; flex-direction: column; overflow: hidden;
}
.post-inner { padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.post-head { display: flex; align-items: flex-start; gap: 10px; }
.avatar {
  width: 32px; height: 32px; flex: none;
  border-radius: 50%; overflow: hidden; background: var(--surface);
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
.who { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.who .name { font: 400 12px/14.64px var(--f-name); color: var(--g01); }
.who .meta { font: 400 10px/13px var(--f-meta); color: var(--g03); }
/* When you saved a post only means something in the list that is ordered by
   it. In the feed it was stamping "just now" on the post you had that second
   saved, which is the one place nobody needs telling. */
.saved-at { display: none; }
#savedView .saved-at {
  margin-left: auto; flex: none; white-space: nowrap;
  height: 24px; display: flex; align-items: center;
  font: 400 12px/1 var(--f-meta); color: var(--g03);
}
.post-head .flame { margin-left: 0; flex: none; padding: 2px; line-height: 0; width: 21px; height: 24px; display: flex; align-items: center; justify-content: center; }
.post-head .flame svg { width: auto; height: 20px; color: var(--primary); opacity: .45; }
.post-head .flame:hover svg { opacity: .8; }
.post-head .flame.on svg { opacity: 1; }

/* Geist is used here and nowhere else — post body copy only */
.post-text {
  font: 400 16px/20.8px var(--f-post); color: var(--g01);
  white-space: pre-wrap; word-wrap: break-word;
}
.post-text a { color: var(--primary); text-decoration: underline; text-underline-offset: 3px; }
.post-text mark { background: var(--primary); color: var(--g09); padding: 0 2px; }
.post-tags { display: flex; flex-wrap: wrap; gap: 6px; }

/* the img carries width/height so the box is reserved before it loads and the
   staggered reveal does not reflow underneath itself */
.post-media { display: grid; gap: 4px; }
.post-media.multi { grid-template-columns: 1fr 1fr; }
.post-media .mi {
  display: block; position: relative; min-width: 0; width: 100%; padding: 0;
  border: 1px solid var(--g04); background: var(--g09); cursor: zoom-in;
}
.post-media .mi:hover { border-color: var(--primary); }
.post-media img { display: block; width: 100%; height: auto; }
.post-media:not(.multi) img { max-height: 560px; object-fit: contain; }
.post-media.multi img { aspect-ratio: 1; height: 100%; object-fit: cover; }
.post-media .play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--g01); pointer-events: none;
}
.post-media .play::before {
  content: ""; position: absolute; width: 62px; height: 62px;
  background: rgba(0,0,0,.45); border: 1px solid rgba(255,255,255,.35);
}
.post-media .play svg { position: relative; width: 26px; height: 26px; }

.post-foot {
  display: flex; align-items: center; gap: 16px;
  padding: 14px 16px; border-top: 1px solid var(--g04);
}
.post-foot .stat { display: inline-flex; align-items: center; gap: 8px; color: var(--g03); font-variant-numeric: tabular-nums; }
.post-foot .stat svg { width: 12px; height: 12px; }
.post-foot .sp { flex: 1; }
/* the download icon only earns its place on mobile, where the labels go */
.post-foot .btn .dl { display: none; }

/* size variants */
/* browse, shuffle and the saved grid all read at the same size, tracking the
   viewport down from 32px rather than sitting fixed; the cards are width-capped
   so there is nothing to gain above that */
.post.md .post-text, .post.lg .post-text {
  font-size: clamp(20px, 2vw, 32px); line-height: 1.32;
}
.post.lg .post-inner { padding: 24px; gap: 14px; }

/* ============================================================
   layout — browse / shuffle
   ============================================================ */
.shell { display: flex; flex: 1; min-height: 0; }

.panel {
  width: 576px; flex: none; background: var(--panel-bg); color: var(--g09);
  display: flex; flex-direction: column;
  position: relative; overflow: hidden auto;
  transition: width .34s cubic-bezier(.16,1,.3,1), padding .34s cubic-bezier(.16,1,.3,1);
  clip-path: polygon(
    0 0,
    calc(100% - var(--notch)) 0,
    100% var(--notch),
    100% 100%,
    var(--notch) 100%,
    0 calc(100% - var(--notch))
  );
  padding: 30px var(--panel-pad) 40px;
  background-image: var(--flame-wm);
  background-repeat: no-repeat;
  background-position: center bottom -40%;
  background-size: auto 50%;
}
.panel > * { position: relative; z-index: 1; }

.about {
  font: 400 15px/22px var(--f-body); color: var(--g09);
  text-align: center; max-width: 480px; margin: 0 auto 26px;
}
.about b { font-weight: 700; }

.panel h2, .modal h2, #mobileMenu h2 {
  font: 400 12px/1 var(--f-ui); letter-spacing: .12em; text-transform: uppercase;
  color: var(--g09); text-align: center; margin: 22px 0 12px;
}
.clear-topics {
  font: 400 11px/1 var(--f-ui); letter-spacing: 0; text-transform: none;
  color: var(--g09); opacity: .7;
  display: inline-flex; align-items: center; gap: 6px; flex: none;
}
.clear-topics .x { display: flex; width: 9px; height: 9px; }
.clear-topics .x svg { width: 100%; height: 100%; }
.clear-topics:hover { opacity: 1; }
/* the aside is three bordered cards in two columns; the saved card is the
   inverted one, and only carries a count and a way through */
.panel-grid { display: grid; grid-template-columns: 1fr 1.15fr; gap: 16px; align-items: stretch; }
.pcol { display: flex; flex-direction: column; gap: 16px; }
.pcard {
  border: 1px solid var(--g09); border-radius: 0;
  background: var(--primary-light);
  padding: 20px; display: flex; flex-direction: column; gap: 14px;
}
.pcard h3 {
  font: 400 12px/1 var(--f-ui); letter-spacing: .12em; text-transform: uppercase;
  color: var(--g09); margin: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.pcard.dark { background: var(--g09); border-color: var(--g09); }
.pcard.dark h3 { color: var(--g02); }
.saved-card { min-height: 152px; }
.saved-card-foot { margin-top: auto; display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; }
.saved-card .big { font: 700 44px/1 var(--f-post); color: var(--primary); letter-spacing: -.02em; }
.saved-card .btn { flex: none; }
.pcard-topics { gap: 16px; }

.topic-wrap { display: flex; flex-wrap: wrap; gap: 8px; }
.misc { display: flex; flex-direction: column; gap: 12px; }
.daterange { display: flex; gap: 10px; align-items: center; }
.pcard .daterange { flex-direction: column; gap: 6px; align-items: stretch; }
.pcard .daterange .datefield { width: 100%; }
.daterange .arr { align-self: center; display: flex; width: 11px; height: 11px; color: var(--g09); }
.daterange .arr svg { width: 100%; height: 100%; }
/* A button, not an <input type="date">. The native popup is browser chrome —
   page CSS cannot reach inside it, so however the input was themed its
   selected day stayed Chromium's blue and its month grid stayed rounded. The
   button keeps a .value and still emits 'change', so nothing downstream of it
   had to change; the calendar it opens is #cal, below. */
.datefield {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  height: 40px; padding: 0 12px; border-radius: var(--radius);
  background: var(--primary); border: 1px solid var(--g09);
  color: var(--g09); font: 400 12px/1 var(--f-ui); font-variant-numeric: tabular-nums;
  text-align: left; cursor: pointer;
}
.daterange .datefield { min-width: 140px; }
.datefield .dv { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.datefield.blank .dv { color: var(--g04); }
.datefield .ci { flex: none; display: flex; width: 14px; height: 14px; opacity: .7; }
.datefield .ci svg { width: 100%; height: 100%; }
.datefield:hover, .datefield:focus-visible,
.datefield[aria-expanded="true"] { background: var(--primary-light); outline: none; }
.datefield:hover .ci, .datefield:focus-visible .ci,
.datefield[aria-expanded="true"] .ci { opacity: 1; }
/* Opening the calendar does not always run through focus, so the strike is
   driven from script. Were it on :focus as well, the cascade would swap
   between the two rules as the class comes off and play it twice. */
.datefield.bstrike { animation: border-strike-alt .2s steps(1, end); }

/* ---------- the calendar ----------
   Always dark, whichever surface the field sits on: every date field on the
   site is on orange, so a dark sheet is what reads as a layer above it. */
.cal {
  position: fixed; z-index: 300; width: 264px; padding: 12px;
  background: var(--g09); border: 1px solid var(--g04);
  font: 400 12px/1 var(--f-ui); color: var(--g02);
}
.cal.on { animation: flash-in .28s steps(1, end) both; }
.cal-head { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; }
.cal-title {
  flex: 1; display: flex; align-items: center; gap: 7px; height: 26px; padding: 0 6px;
  font: 400 13px/1 var(--f-ui); color: var(--g01); cursor: pointer;
}
.cal-title:hover { background: var(--g04); }
.cal-title .cv { display: flex; width: 9px; height: 9px; color: var(--g03); }
.cal-title .cv svg { width: 100%; height: 100%; }
.cal-title.flat { cursor: default; }
.cal-title.flat:hover { background: none; }
.cal-title.flat .cv { display: none; }
.cal-nav { flex: none; display: grid; place-items: center; width: 26px; height: 26px; color: var(--g02); cursor: pointer; }
.cal-nav svg { width: 13px; height: 13px; }
.cal-nav:hover:not(:disabled) { background: var(--g04); color: var(--g01); }
.cal-nav:disabled { color: var(--g04); cursor: default; }
.cal-dow, .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.cal-dow[hidden] { display: none; }
.cal-dow span {
  display: grid; place-items: center; height: 22px;
  font-size: 11px; color: var(--g03);
}
.cal-grid button {
  height: 30px; display: grid; place-items: center; cursor: pointer;
  font: 400 12px/1 var(--f-ui); font-variant-numeric: tabular-nums; color: var(--g02);
}
.cal-grid button.out { color: var(--g04); }
.cal-grid button:hover:not(:disabled), .cal-grid button:focus-visible {
  background: var(--g04); color: var(--g01); outline: none;
}
.cal-grid button:disabled { color: #2A2624; cursor: default; }
/* the day this field holds, the day the other end holds, and the span between */
.cal-grid button.in { background: rgba(255, 92, 0, .14); }
.cal-grid button.edge { box-shadow: inset 0 0 0 1px var(--primary-dark); }
.cal-grid button.on, .cal-grid button.on:hover {
  background: var(--primary); color: var(--g09);
}
.cal-grid.months { grid-template-columns: repeat(3, 1fr); }
.cal-grid.years { grid-template-columns: repeat(4, 1fr); }
.cal-grid.months button, .cal-grid.years button { height: 36px; }
.cal-foot {
  display: flex; justify-content: space-between; gap: 12px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--g04);
}
.cal-foot button { font: inherit; color: var(--primary); text-decoration: underline; cursor: pointer; }
.cal-foot button:hover { color: var(--primary-light); }
.daterange span { font: 400 12px/1 var(--f-ui); color: var(--g09); }

.panel-cta { display: flex; justify-content: center; }
.credit {
  margin-top: auto; padding-top: 34px; text-align: center;
  font: 400 13px/1 var(--f-ui); color: var(--g09);
}
.credit a { text-decoration: underline; }

.feed-wrap { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.feed-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 14px 22px 10px;
  width: 100%; max-width: 744px; margin: 0 auto;
  font: 400 12px/1 var(--f-ui); color: var(--g03);
}
.feed-bar b { color: var(--g01); font-weight: 400; font-variant-numeric: tabular-nums; }
.feed-outer { position: relative; flex: 1; min-height: 0; }
.feed { height: 100%; overflow-y: auto; padding: 0 22px 40vh; }
.feed-inner, .shuffle-inner { width: 100%; max-width: 700px; margin: 0 auto; }
.load-more {
  display: flex; width: 100%; justify-content: center; gap: 10px;
  padding: 14px; margin-bottom: 54px;
}
.load-more .rest { color: var(--g03); }
.load-more:hover .rest { color: var(--g02); }
.fade { position: absolute; left: 0; right: 10px; height: var(--fade-h); pointer-events: none; z-index: 5; }
.fade-top { top: 0;    background: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.92) 22%, rgba(0,0,0,.45) 55%, transparent 100%); }
.fade-bot { bottom: 0; background: linear-gradient(to top,    #000 0%, rgba(0,0,0,.92) 22%, rgba(0,0,0,.45) 55%, transparent 100%); }
.feed .post { width: 100%; margin: 0 0 54px; }

.shuffle-stage {
  flex: 1; min-height: 0; overflow-y: auto; padding: 20px 22px 60px;
  display: flex; flex-direction: column; align-items: center; gap: 16px;
}
.shuffle-stage .post { width: 100%; }
.shuffle-nav { display: flex; gap: 14px; width: 100%; margin-top: auto; }
.shuffle-nav .btn { flex: 1; justify-content: center; }

.empty {
  padding: 60px 20px; text-align: center; color: var(--g03);
  font: 400 13px/1.6 var(--f-ui);
}

/* ============================================================
   modal — topic picker
   ============================================================ */
.modal-bg {
  position: fixed; inset: 0; z-index: 80; background: rgba(0,0,0,.6);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.modal {
  background: var(--panel-bg); color: var(--g09); border-radius: var(--radius);
  width: 420px; max-width: 100%; padding: 22px; box-shadow: 0 20px 60px rgba(0,0,0,.5);
}
.modal .grab {
  width: 90px; height: 5px; margin: 0 auto 16px; background: none;
  border-top: 1px solid var(--g09); border-bottom: 1px solid var(--g09);
}

/* One post on its own, on the surface the card already uses rather than the
   orange of the sheets — it is the post you are reading, not a control panel.
   The strip at the top is for the close button, so it never sits over the
   flame in the card's own corner. */
.reader-bg { z-index: 85; padding: 52px 14px 14px; background: rgba(0,0,0,.88); }
.reader { width: 100%; max-height: 100%; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.reader .post { max-width: none; }
.reader-close {
  position: absolute; right: 12px; top: 10px; z-index: 2;
  border: none; background: none; padding: 8px; color: var(--g01);
  display: flex; line-height: 0;
}
.reader-close:hover { background: none; color: var(--primary); }
.reader-close svg { width: 22px; height: 22px; }

/* The menu is a drawer off the right edge, not a full-width sheet: the page
   stays visible and dimmed down the left. It carries the aside's surface —
   same orange, notched corners, watermark, credit on the bottom edge. */
#menuBg { align-items: stretch; justify-content: flex-end; padding: 0; }
#mobileMenu {
  width: 90%; max-width: 430px; position: relative; overflow-y: auto;
  background: var(--panel-bg); color: var(--g09);
  display: flex; flex-direction: column;
  padding: 68px 28px 34px;
  clip-path: polygon(
    var(--notch) 0,
    100% 0,
    100% 100%,
    var(--notch) 100%,
    0 calc(100% - var(--notch)),
    0 var(--notch)
  );
  background-image: var(--flame-wm);
  background-repeat: no-repeat;
  background-position: center bottom -40%;
  background-size: auto 50%;
  animation: drawer-in .2s cubic-bezier(.16,1,.3,1),
             surface-strike .22s steps(1, end);
}
@keyframes drawer-in  { from { transform: translateX(100%); } to { transform: none; } }
@keyframes drawer-out { from { transform: none; } to { transform: translateX(100%); } }
#menuBg.closing { animation: flash-out .2s steps(1, end) forwards; }
/* the drawer leaves on a blowout rather than a flicker; every step states the
   colour so none of them interpolate back to white */
@keyframes surface-strike {
  0%   { background-color: var(--g01); }
  22%  { background-color: var(--panel-bg); }
  44%  { background-color: var(--g01); }
  66%  { background-color: var(--panel-bg); }
  100% { background-color: var(--panel-bg); }
}
@keyframes surface-strike-out {
  0%   { background-color: var(--g01); }
  22%  { background-color: var(--panel-bg); }
  44%  { background-color: var(--g01); }
  66%  { background-color: var(--panel-bg); }
  100% { background-color: var(--panel-bg); }
}
#menuBg.closing #mobileMenu {
  animation: drawer-out .22s cubic-bezier(.7,0,.84,0) forwards,
             surface-strike-out .22s steps(1, end) both;
}
#mobileMenu > * { position: relative; }
#mobileMenu .about { margin: 0 auto 30px; }
#mobileMenu .saved-card { min-height: 150px; }
/* Data sits under the saved card, on the panel's own rhythm; the credit still
   takes the slack below it, so the pair never drifts to the foot of a tall
   drawer */
#mobileMenu .panel-cta { gap: 10px; }
#mobileMenu .credit { margin-top: auto; padding-top: 40px; }
#menuClose {
  position: absolute; right: 20px; top: 18px; z-index: 2;
  border: none; padding: 6px; color: var(--g09);
}
#menuClose:hover { background: none; color: var(--g09); }
#menuClose svg { width: 22px; height: 22px; }
@keyframes sheet-up   { from { transform: translateY(100%); } to { transform: none; } }
@keyframes sheet-down { from { transform: none; } to { transform: translateY(100%); } }
/* runs at every width, so animationend fires even where the sheet does not slide */
#filterBg.closing, #lightBg.closing { animation: flash-out .2s steps(1, end) forwards; }
.modal h2:first-of-type { margin-top: 0; }
.modal .submit { width: 100%; margin-top: 20px; justify-content: center; }
#filterSheet .misc { gap: 14px; }
/* The pair reads as one range, so it is one row: from, across, to. The fields
   share it evenly and may shrink past their desktop minimum — there is only a
   date in them, and two stacked fields cost a third of the sheet. */
#filterSheet .daterange { gap: 10px; align-items: center; }
#filterSheet .daterange .datefield { flex: 1; min-width: 0; }

/* ============================================================
   lightbox
   ============================================================ */
.lightbox {
  background: rgba(0,0,0,.92); z-index: 95;
  display: flex; align-items: center; justify-content: center; padding: 56px 20px;
}
.lb-stage { display: flex; align-items: center; justify-content: center; max-width: 100%; max-height: 100%; }
.lb-stage img, .lb-stage video {
  display: block; max-width: 100%; max-height: calc(100vh - 130px);
  border: 1px solid var(--g04); background: var(--g09);
}
.lb-close, .lb-nav {
  position: absolute; z-index: 2; display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; color: var(--g02);
  background: var(--g09); border: 1px solid var(--g04);
}
.lb-close:hover, .lb-nav:hover { color: var(--g09); background: var(--primary); border-color: var(--primary); }
.lb-close { top: 16px; right: 16px; }
.lb-close svg { width: 20px; height: 20px; }
.lb-nav svg { width: 22px; height: 22px; }
.lb-nav.prev { left: 16px; }
.lb-nav.next { right: 16px; }
.lb-src {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 16px;
  font: 400 12px/1 var(--f-ui); color: var(--g03); text-decoration: underline;
}
.lb-src:hover { color: var(--primary); }
@media (max-width: 860px) {
  .lightbox { padding: 56px 10px; }
  .lb-nav { top: auto; bottom: 16px; }
  .lb-nav.prev { left: 10px; }
  .lb-nav.next { right: 10px; }
  .lb-src { bottom: 28px; }
}

/* ============================================================
   toast
   ============================================================ */
.toast {
  position: fixed; right: 24px; bottom: 24px; z-index: 90;
  background: var(--primary); color: var(--g09); border: 1px solid var(--primary);
  padding: 12px 18px; font: 400 13px/1 var(--f-ui);
  opacity: 0; pointer-events: none;
}

/* It does not travel — it strikes. Both keyframes blow the whole chip out to
   white for a frame before settling or leaving, and every step holds, so it
   reads as a bulb firing rather than anything easing. Segments that set no
   background fall back to the element's own, which is what produces the
   blowout-then-orange stutter. */
/* ============================================================
   struck — the white blowout

   Reserved for a state being committed: a save, a filter going on, the view
   changing. Not for reveals or hovers, where it would stop meaning anything.

   It is an overlay rather than an animation on the element's own background,
   so it works on a badge, a button or the whole page without any of them
   restating their colours — and only opacity animates, which avoids the
   interpolation the toast keyframes had to work around.
   ============================================================ */
@keyframes struck-flash {
  0%   { opacity: 1; }
  25%  { opacity: 0; }
  50%  { opacity: 1; }
  75%  { opacity: 0; }
  100% { opacity: 0; }
}
.struck { position: relative; }
.struck::after {
  content: ""; position: absolute; inset: 0; z-index: 3;
  background: var(--g01); pointer-events: none;
  animation: struck-flash .2s steps(1, end) both;
}
/* an icon or a numeral blows out its ink instead — a white block over a glyph
   would just hide it */
@keyframes struck-ink {
  0%   { color: var(--g01); }
  25%  { color: inherit; }
  50%  { color: var(--g01); }
  100% { color: inherit; }
}
.flame.struck::after, .count-strike.struck::after { content: none; }
.flame.struck svg { animation: struck-ink .2s steps(1, end) both; color: var(--primary); }
.count-strike.struck { animation: struck-ink .2s steps(1, end) both; }
/* the results number is already white, so it blows out to the accent instead;
   every step states its colour rather than inheriting one */
@keyframes count-flash {
  0%   { color: var(--primary); }
  25%  { color: var(--g01); }
  50%  { color: var(--primary); }
  100% { color: var(--g01); }
}
#resultCount.struck::after { content: none; }
#resultCount.struck { animation: count-flash .2s steps(1, end) both; }
@keyframes count-flash-alt {
  0%   { color: var(--g09); }
  25%  { color: var(--g01); }
  50%  { color: var(--g09); }
  100% { color: var(--g01); }
}
body.accent-shared #resultCount.struck { animation: count-flash-alt .2s steps(1, end) both; }

/* the view change: the surfaces blow white, the content on them does not */
body.bg-struck .panel { background: var(--g01); }

@keyframes toast-in {
  0%   { opacity: 0;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  10%  { opacity: 1;   background: var(--g01); border-color: var(--g01); color: var(--g09); }
  18%  { opacity: 0;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  30%  { opacity: 1;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  42%  { opacity: 1;   background: var(--g01); border-color: var(--g01); color: var(--g09); }
  52%  { opacity: .25; background: var(--primary); border-color: var(--primary); color: var(--g09); }
  66%  { opacity: 1;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  80%  { opacity: .55; background: var(--primary); border-color: var(--primary); color: var(--g09); }
  100% { opacity: 1;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
}
@keyframes toast-out {
  0%   { opacity: 1;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  12%  { opacity: 1;   background: var(--g01); border-color: var(--g01); color: var(--g09); }
  26%  { opacity: 0;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  40%  { opacity: 1;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  54%  { opacity: 0;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
  70%  { opacity: 1;   background: var(--g01); border-color: var(--g01); color: var(--g09); }
  84%  { opacity: .3;  background: var(--primary); border-color: var(--primary); color: var(--g09); }
  100% { opacity: 0;   background: var(--primary); border-color: var(--primary); color: var(--g09); }
}
.toast.on  { pointer-events: auto; animation: toast-in .42s steps(1, end) both; }
.toast.off { pointer-events: none; animation: toast-out .38s steps(1, end) both; }

/* its own bar, outside .feed-wrap, so it stays put when the saved view takes
   over from the feed */
.mobile-tabs { display: none; padding: 10px 14px 0; }
.mobile-tabs .mode { flex: 1; justify-content: center; }
.mobile-tabs .n { color: var(--primary); font-variant-numeric: tabular-nums; }
.mobile-tabs .mode[aria-pressed='true'] .n { color: var(--g04); }
/* One rhythm down the header: 7px from the tabs to the search, and 7px from
   the search to the results line. The gap below is the feed bar's own top
   padding, so this row carries none of it. */
.mobile-controls { display: none; flex-direction: column; gap: 12px; padding: 7px 14px 0; }
.mobile-controls .row { display: flex; gap: 10px; align-items: center; }
.mobile-controls .row .field { flex: 1; }
/* the primary control beside the search: everything else lives behind it */
.icon-btn {
  flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 40px; min-width: 40px; padding: 0 10px;
  background: var(--primary); border: 1px solid var(--primary); color: var(--g09);
  font: 400 12px/1 var(--f-ui);
}
.icon-btn:hover { background: var(--primary-light); border-color: var(--primary-light); }
.icon-btn .i { display: flex; }
.icon-btn svg { width: 20px; height: 20px; }
.icon-btn .n { font-variant-numeric: tabular-nums; }
body.accent-shared .icon-btn { background: var(--g09); border-color: var(--g09); color: var(--primary); }
/* the row label only: the checkbox labels are nested in .check and stay
   sentence case */
.mobile-controls .row > .lbl {
  font: 400 12px/1 var(--f-ui); letter-spacing: .1em; text-transform: uppercase; color: var(--g01);
  flex: none; width: 62px;
}

/* ============================================================
   responsive
   ============================================================ */
/* Between the mobile breakpoint and roughly 1320px the nav cannot fit the
   wordmark, the search and three segments at full size, so everything gives a
   little rather than the search collapsing to nothing. */
@media (max-width: 1320px) {
  .nav { gap: 12px; }
  .nav .brand { flex: none; --mark-h: 42px; }
  .nav .brand-word { font-size: 20px; line-height: 26px; white-space: nowrap; }
  .nav .brand-tag { font-size: 10px; line-height: 14px; }
  .nav #navSearchWrap { min-width: 150px; }
  .mode { padding: 0 11px; font-size: 14px; }
  .nav-shell { padding-bottom: 0; }
}

@media (max-width: 1080px) {
  .nav .brand { --mark-h: 34px; }
  .nav .brand-word { font-size: 15px; line-height: 20px; }
  .nav .brand-tag { font-size: 9px; line-height: 12px; }
  .nav #navSearchWrap { min-width: 130px; }
  .mode { padding: 0 9px; font-size: 13px; }
}

@media (max-width: 1180px) {           /* tablet: hold desktop, shrink the panel */
  .panel { width: 420px; --panel-pad: 22px; padding: 24px var(--panel-pad) 32px; }
  .panel-grid { grid-template-columns: 1fr; }   /* too narrow for two columns of badges */
  .pcol { display: contents; }
  .panel-grid .saved-card   { order: 1; }
  .panel-grid .pcard-topics { order: 2; }
  .panel-grid .dates-card   { order: 3; }
  .panel-grid .misc-card    { order: 4; }
  .feed .post, .shuffle-stage .post, .shuffle-nav { max-width: none; }
}

@media (max-width: 860px) {            /* mobile */
  .nav { padding: 10px 14px; gap: 12px; }
  :root { --page-pad: 8px; }
  .nav .brand-word { font-size: 12px; line-height: 16px; }
  .nav .brand-tag { font-size: 9px; line-height: 12px; }
  .nav .brand { --mark-h: 30px; gap: 7px; min-width: 0; max-width: calc(100% - 64px); }
  /* stacking the subheading costs the mark's width, so on the narrowest
     phones it gives way rather than running under the corner */
  .nav .brand-text { overflow: hidden; }
  .nav .brand-tag { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* the mobile controls carry search and the segments, so the nav keeps only
     the wordmark and the hamburger — leaving them in overflowed the row */
  .nav .nav-right, .nav .nav-spacer { display: none; }
  /* the nav's corner notch clips exactly where this button sat, so it is
     placed on the orange above the clip instead, which is where the design
     puts it anyway */
  .nav-shell { position: relative; }
  .hamburger {
    display: flex; align-items: center; padding: 6px;
    position: absolute; right: 12px; top: 50%; transform: translateY(-50%); z-index: 10;
  }
  .hamburger svg { width: 26px; height: 26px; color: var(--g09); }
  .nav {
    background: var(--g09);
    /* only has to clear the hamburger, and the brand needs the room */
    clip-path: polygon(0 0, calc(100% - 44px) 0, calc(100% - 80px) 100%, 0 100%);
  }
  .nav-shell { background: var(--panel-bg); }
  /* the corner notch, struck before the drawer opens */
  .nav-shell.struck-bg { background: var(--g01); }

  .shell { flex-direction: column; }
  /* the aside is desktop-only, but the saved view lives inside it, so the
     expanded state has to come back for that one view */
  .panel { display: none; }
  /* flex:none on the stacked shell let it grow to its content, so the grid
     inside never got a bounded height and nothing could scroll */
  .panel.expanded { display: flex; width: 100%; flex: 1; min-height: 0; }
  .mobile-controls { display: flex; }
  /* nothing morphs here, so the panel must not animate its box either */
  .panel { transition: none; background: transparent; }
  body.view-tint .panel { background: var(--panel-bg); }
  .panel.swap-out { transition: opacity .1s steps(4, jump-start); }
  .mobile-tabs { display: flex; }
  .feed .post, .shuffle-stage .post { max-width: none; }
  /* The wash sets its own clearance: the feed pads by it so the first card
     starts below it rather than under it. At 70 that clearance was costing
     a tenth of the screen before a single post — the gradient still reads
     at 40, and the posts start that much sooner. */
  :root { --fade-h: 40px; }
  .feed { padding: var(--fade-h) 14px 40px; }
  .shuffle-stage { padding: 0 14px 40px; }
  /* The wash at the foot of the list greyed out the post you were still
     reading, on a screen where a post often fills the whole of it. The one at
     the head stays: it has the nav above it to soften. */
  .fade-bot { display: none; }
  /* The search matches the filter button beside it: 34 against 40 left the two
     misaligned at both edges. The row was already 40 tall — the button set it —
     so the search gains the height and the header gains none. */
  .mobile-controls .row .field { height: 40px; }
  .post-text { cursor: pointer; }
  .reader .post-text { cursor: auto; }
  .post-foot { gap: 10px; padding: 12px 14px; }
  .post-foot .btn { white-space: nowrap; }
  /* the two labelled buttons ran off the card on a phone, so they drop to
     their icons — bigger, and padded out to a real tap target */
  .post-foot .btn .lbl { display: none; }
  .post-foot .btn .dl { display: flex; }
  .post-foot .btn { padding: 6px 8px; }
  .post-foot .btn svg { width: 16px; height: 16px; }
}

/* active topic chips shown next to the results count */
.active-topics { display: flex; gap: 6px; flex-wrap: wrap; }
.active-topics .badge { cursor: default; }
.active-topics .x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 13px; height: 13px; margin-left: 2px; cursor: pointer; color: currentColor; opacity: .6;
}
.active-topics .x:hover { opacity: 1; }
.active-topics .x svg { width: 10px; height: 10px; }

/* nav saved button */
/* the saved segment carries a flame and a count; both invert with the segment */
.mode .fl { width: 14px; height: 17px; display: flex; color: var(--primary); }
.mode .fl svg { width: 100%; height: 100%; }
.mode .n { color: var(--primary); font-variant-numeric: tabular-nums; }
.mode[aria-pressed='true'] .fl { color: var(--g09); }
.mode[aria-pressed='true'] .n { color: var(--g04); }

/* sort controls sharing the results row */
.feed-bar .sp { flex: 1; }
.feed-bar .sort-lbl {
  font: 400 12px/1 var(--f-ui); letter-spacing: .1em; text-transform: uppercase; color: var(--g03);
}
body.accent-shared .feed-bar .sort-lbl { color: var(--g04); }
/* one segmented control, the same as the nav modes: no gap, one shared edge,
   and the current segment on top so its border wins */
/* display:contents keeps the desktop bar one flat row; on mobile the label,
   the segments and the direction stay together and wrap as a block, so a
   four-digit count and a two-digit one lay out the same way */
.sort-unit { display: contents; }
.sortset { display: flex; }
.sortset .badge + .badge { margin-left: -1px; }
.sortset .badge.on { position: relative; z-index: 1; }
/* Scoped to the control rather than the bar it used to live in: on a phone it
   is moved into the filter sheet, and the arrow collapsed to nothing the
   moment it left .feed-bar behind. */
.sort-unit .sortset .badge, #dirBtn { padding: 5px 11px; text-transform: none; }
#dirBtn { display: inline-flex; align-items: center; gap: 6px; }
#dirBtn .di { display: flex; width: 11px; height: 11px; }
#dirBtn .di svg { width: 100%; height: 100%; }

/* ============================================================
   saved view — same document, morphs from the filter panel
   ============================================================ */
.crumb {
  display: flex; align-items: center; gap: 8px; padding: 20px 26px 12px;
  font: 400 12px/1 var(--f-ui); letter-spacing: .08em; text-transform: uppercase; color: var(--g09);
}
.crumb button { font: inherit; letter-spacing: inherit; text-transform: inherit; text-decoration: underline; }
.crumb .sep { opacity: .6; }

/* the segmented tabs say where you are at every width, so the breadcrumb
   earns nothing; the count it carried moved into the bar */
.crumb { display: none; }
.saved-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 20px 26px 18px;
}
/* every group but the search bar opens with its label, so the label carries
   the space that separates the groups from each other */
.back-btn { flex: none; gap: 6px; padding: 5px 11px; margin-right: 24px; }
.back-btn svg { width: 12px; height: 12px; }
.saved-bar .res { font-variant-numeric: tabular-nums; color: var(--g04); }
.saved-bar .lbl {
  font: 400 12px/1 var(--f-ui); letter-spacing: .1em; text-transform: uppercase; color: var(--g09);
  margin-left: 24px;
}
.sortset { display: flex; }   /* segmented; the shared-edge rules are above */
/* display:contents keeps the desktop bar a single flat flex row; on mobile the
   group becomes a real box so its label and controls wrap together */
.bar-group { display: contents; }
.saved-bar .daterange .datefield { border-color: var(--g09); }
.saved-grid {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding: 0 26px 40px;
}
.masonry { display: flex; gap: 18px; align-items: flex-start; }
.mcol { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 18px; }
.saved-grid .post { width: 100%; margin: 0; }
@media (max-width: 860px) {
  /* the topic picker rises from the bottom edge rather than floating centred */
  #filterBg { align-items: flex-end; padding: 0; }
  #filterBg .modal {
    width: 100%; max-width: none;
    padding: 16px 16px calc(20px + env(safe-area-inset-bottom, 0px));
    animation: sheet-up .2s cubic-bezier(.16,1,.3,1),
               surface-strike .22s steps(1, end) .16s forwards;
  }
  /* the sheet leaves the way the drawer does */
  #filterBg.closing .modal {
    animation: sheet-down .22s cubic-bezier(.7,0,.84,0) forwards,
               surface-strike-out .22s steps(1, end) both;
  }
  .saved-grid { padding: 0 14px 30px; }
  /* the design gives mobile saved a sort row and a topic row; search keeps a
     row of its own and the date range is desktop-only */
 /* one gutter and one row rhythm across both headers: 14px in from the edge,
     12px between rows, and 28px before the sort band the way the browse
     feed bar is separated from the controls above it */
  .saved-bar { padding: 14px 14px; gap: 12px; }
  .saved-bar .bar-group.sort { margin-top: 16px; }
  .feed-bar { padding: 7px 14px 8px; }
  .feed-bar .sp { display: none; }
  .sort-unit { display: flex; align-items: center; gap: 12px; flex-wrap: nowrap; }
  /* in the sheet the h2 above it says "Sort by", so the inline label would say
     it twice; the row spreads to the full width it now has */
  .sheet-sort .sort-unit { width: 100%; gap: 10px; }
  .sheet-sort .sort-lbl { display: none; }
  .sheet-sort .sortset { flex: 1; }
  .sheet-sort .sortset .badge { flex: 1; justify-content: center; }
  .saved-bar .lbl { margin-left: 0; width: 60px; flex: none; }
  .saved-bar > .field { flex: 0 0 100%; max-width: none; }
  .bar-group { display: flex; align-items: center; gap: 10px; flex: 0 0 100%; }
  .saved-bar .dates-lbl, .saved-bar .daterange { display: none; }
  .saved-bar .dd { flex: 1; }
  .saved-bar .dd .select-topic { width: 100%; min-width: 0; }
  .dd-menu { min-width: 0; width: 100%; }

  /* the saved view borrows the browse header here, so its own bar is dropped
     rather than restyled to match */
  .saved-bar { display: none; }
  /* .view-tint is the colour and lands on the click; .view-saved is the
     layout and waits until the outgoing list is invisible */
  body.view-saved .feed-wrap { flex: none; order: 0; }
  body.view-saved .panel.expanded { order: 1; }
  /* the borrowed header is on orange now, so its plain text follows the
     Accent variants the controls themselves switch to */
  body.accent-shared .feed-bar { color: var(--g04); }
  body.accent-shared .feed-bar b { color: var(--g09); }
  body.accent-shared .mobile-controls .row > .lbl { color: var(--g09); }
  /* everything under the nav is one orange field on this view */
  body.view-tint .mobile-tabs { background: var(--panel-bg); }
  body.view-tint .shell { background: var(--panel-bg); }
  /* on the orange the segments take the accent theme, the same inversion
     .badge.alt uses: black border at rest, black fill when current */
  body.view-tint .mobile-tabs .mode {
    background: transparent; border-color: var(--g09); color: var(--g09);
  }
  body.view-tint .mobile-tabs .n { color: var(--g04); }
  body.view-tint .mobile-tabs .mode[aria-pressed="true"] {
    background: var(--g09); border-color: var(--g09); color: var(--g02);
  }
  body.view-tint .mobile-tabs .mode[aria-pressed="true"] .n { color: var(--g03); }
  /* same running order as the browse header: search, topics, then sort */
  .saved-bar > .field { order: 1; }
  .saved-bar .bar-group.topics { order: 2; }
  .saved-bar .bar-group.sort { order: 3; flex-wrap: wrap; }
  .saved-bar .res b { color: var(--g09); font-weight: 400; }
}

/* ============================================================
   surface expansion — the orange panel IS the saved container
   Width animates on one persistent element, so nothing cross-fades; only
   the contents inside swap.
   ============================================================ */
.panel.expanded {
  width: 100%;
  padding: 0;
  overflow: hidden;
}
.surface-view { display: flex; flex-direction: column; min-height: 0; }
#filterView { flex: 1; }
.panel.expanded #savedView { flex: 1; min-height: 0; }
.surface-view[hidden] { display: none !important; }

/* contents fade out, the box resizes, contents fade back in */
.surface-view { opacity: 1; }
.surface-view.out { opacity: 0; animation: flash-out .16s steps(1, end) both; }

/* staggered reveal, shared by the browse list and the saved grid: the
   transition lives on .in, so the hidden state lands instantly and only the
   entry is animated */
/* the cards strike one after another; riseIn hands out the delays */
.post.rise { opacity: 0; }
.post.rise.in { animation: flash-in .3s steps(1, end) both; }
.feed-wrap { opacity: 1; }
.feed-wrap.leaving { opacity: 0; animation: flash-out .16s steps(1, end) both; }
/* the mobile list swap: only the list fades, never the header around it */
/* stepped on the way out too, so nothing in the app ever ramps */
.swap-out { opacity: 0 !important; transition: opacity .12s steps(4, jump-start); }
.feed-wrap.leaving { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .panel, .feed-wrap { transition: none; }
  .surface-view, .surface-view.out, .feed-wrap.leaving { animation: none; }
  .toast.on, .toast.off { animation: none; }
  .field:focus-within, .field.alt:focus-within, .datefield.bstrike { animation: none; }
  .cal.on { animation: none; }
  .struck::after, .flame.struck svg, .count-strike.struck { animation: none; }
  body.bg-struck .panel { background: none; }
  .struck::after { content: none; }
  .toast.on { opacity: 1; }
  #filterBg .modal, #filterBg.closing, #filterBg.closing .modal,
  #mobileMenu, #menuBg.closing, #menuBg.closing #mobileMenu { animation: none; }
  .post.rise { opacity: 1; transform: none; }
  .rise-in { animation: none; }
}

/* Induction is a wide face: the wordmark alone is ~250px at 12px, so the
   narrowest phones need one more step down. */
@media (max-width: 400px) {
  .nav .brand-word { font-size: 10px; line-height: 14px; }
  .nav .brand-tag { font-size: 8px; line-height: 11px; }
  .nav .brand { --mark-h: 26px; }
}
