/* SubStandby: minimal, no frameworks. System fonts, one accent, whitespace does the work. */

:root{
  --ink:#1a1a1a;
  --muted:#6f6f6f;
  --faint:#6b7280; /* 4.83:1 on white, WCAG AA for normal text */
  --line:#e7e7e7;
  --bg:#ffffff;
  --wash:#f7f7f7;
  /* Option A (Noah, 2026-09-25): two-tone amber. --amber (#EAB308) is the
     bright brand yellow for area fills and surfaces carrying dark ink;
     --amber-deep (#A16207, ~4.9:1 on white) is the dark gold for strokes,
     lines, and amber-colored text on white. Bright yellow is never text
     or a thin stroke on white. (--accent stays the UI amber for buttons,
     badges, and the active-tab underline.) */
  --amber:#EAB308;
  --amber-deep:#A16207;
  /* R12: pale-yellow wash for explainer cards, planner scards and the savings
     hero box. --amber at 13% reads as a soft yellow tint, clearly yellow not
     orange. (--wash stays the neutral gray used elsewhere.) */
  --ywash:color-mix(in srgb, var(--amber) 13%, #fff);
  --star:#B45309; /* M11: was #d97706 (~3.3:1); dark gold holds AA on white */
  --accent:#B45309; /* 5.02:1 on white, WCAG AA for text (D20, computed 2026-09-22) */
  --maxw:880px;
  /* QC 2026-09-25: single h2 size + single content measure tokens. */
  --text-h2:20px;
  --measure:62ch;
}

*{box-sizing:border-box}
[hidden]{display:none !important}

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  font-size:17px;
  line-height:1.6;
}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 20px}

/* ---------- header ---------- */

header{padding:30px 0 14px}
/* Slim tab bar: the only thing that persists on scroll (mobile). The brand
   block above scrolls away; the dataline lives in the footer. */
.tabbar{border-bottom:1px solid var(--line)}
header h1{margin:0;font-size:42px;letter-spacing:-.5px;font-weight:700}
header #site-name{margin:0;font-size:42px;letter-spacing:-.5px;font-weight:700}
.tagline{margin:2px 0 10px;color:var(--muted)}

nav{display:flex;flex-wrap:wrap;gap:20px;margin:6px 0}
nav a{color:var(--ink);text-decoration:none;padding:2px 0;border-bottom:2px solid transparent}
@media (hover:hover){
  /* QC 2026-09-25: nav hover must never gray out — amber underline instead. */
  nav a:not(.active):hover{color:var(--ink);border-bottom-color:var(--ink)}
}
nav a.active{border-bottom-color:var(--accent);font-weight:600}

.dataline{font-size:14px;color:var(--muted);margin:8px 0 0}
.dataline .stale{color:var(--accent);font-weight:600}
/* Dataline lives in the footer now, as a footnote above the footcols. */
footer .dataline{margin:0 0 14px}

/* Content sub-nav: labeled as a group ("More"), visually secondary, and it
   scrolls away with the page -- only the .tabbar persists. */
.content-nav{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 18px;margin:10px 0 0}
.content-nav-label{font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-right:2px}
.content-nav a{font-size:15px;color:var(--muted);text-decoration:none}
.content-nav a[aria-current="page"]{color:var(--ink);font-weight:600}
@media (hover:hover){
  .content-nav a:hover{color:var(--ink);text-decoration:underline}
}

/* ---------- generic ---------- */

h2{font-size:var(--text-h2);margin:26px 0 10px;letter-spacing:-.2px}
h3{font-size:18px;margin:26px 0 8px}
.note{color:var(--muted);font-size:15px}
a{color:inherit}

button{
  font:inherit;cursor:pointer;background:#fff;color:var(--ink);
  border:1px solid var(--line);border-radius:6px;padding:4px 12px;
}
/* QC 2026-09-25: one subtle pressed state for every button. */
button:active{transform:translateY(1px)}
@media (hover:hover){
  button:hover{border-color:var(--faint)}
}

/* ---------- catalog ---------- */

.controls{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:14px 0 18px}
.controls input[type=search]{
  font:inherit;padding:6px 12px;border:1px solid var(--line);border-radius:6px;
  min-width:200px;flex:1 1 200px;
}
.controls select{font:inherit;padding:6px 10px;border:1px solid var(--line);border-radius:6px;background:#fff}

.chips{display:flex;flex-wrap:wrap;gap:8px}
.chipbtn{font-size:14px;padding:4px 12px;border-radius:999px;display:inline-flex;align-items:center}
.chipbtn.on{background:var(--ink);color:#fff;border-color:var(--ink)}
/* disabled must never look clickable */
button:disabled{opacity:.5;cursor:default;pointer-events:none;border-style:dashed}

.sec-sub{color:var(--muted);font-size:14px;margin:-6px 0 14px;max-width:var(--measure)}

/* boot failure: the show data did not load */
.boot-error{max-width:var(--measure);padding:18px;border:1px solid var(--line);border-radius:8px;background:#fff}
.boot-error .note strong{color:var(--ink)}
.boot-fix{margin-top:12px;font-size:14px;color:var(--muted)}
.boot-fix summary{cursor:pointer;color:var(--ink);font-weight:600}
.boot-fix ol{margin:8px 0 0;padding-left:22px}
.boot-fix li{margin:6px 0}

.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:14px}
/* R1: 270px floor guarantees the 228px star row fits inside card padding
   at every column count (250px cards could clip it by ~10px). */
.card{border:1px solid var(--line);border-radius:8px;padding:14px 16px;background:#fff}
/* Mira Okafor tile inspiration: desktop hover lifts the card with a soft shadow. */
@media (hover:hover){
  .card,.scard{transition:transform .18s ease,box-shadow .18s ease,border-color .18s ease}
  .card:hover,.scard:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.10);border-color:var(--faint)}
}
.card h3{margin:6px 0 4px;font-size:18px}
.card .svc{font-size:14px;color:var(--muted)}
.card .meta{font-size:14px;color:var(--muted);margin:4px 0}
.card .next{font-size:15px;margin:8px 0}
/* popular cards: no rank = no next line; empty <p> must not leave a gap */
.card .next:empty{display:none}
/* popular cards: no rank = no next line; empty <p> must not leave a gap */
.card .next:empty{display:none}
.card .actions{margin-top:10px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.card .sched{font-size:13px;color:var(--faint);margin:8px 0 0}

.dot{display:inline-block;width:10px;height:10px;border-radius:50%;background:var(--c,#999);margin-right:6px;flex:none}
/* Live-show radar dot (Mira Okafor availability ping): an expanding ring in the
   service color on cards whose season is currently airing. Pure CSS; inert under
   prefers-reduced-motion via the global P1 rule. */
.dot.live{position:relative}
.dot.live::after{content:"";position:absolute;inset:-4px;border-radius:50%;
  border:1.5px solid var(--c,#999);animation:dotPing 2.2s ease-out infinite;pointer-events:none}
@keyframes dotPing{0%{transform:scale(.45);opacity:.9}70%{opacity:.25}100%{transform:scale(1.15);opacity:0}}

.stars{display:inline-flex;gap:2px}
.stars button{border:none;background:none;padding:2px 3px;font-size:17px;color:#8c8c8c;line-height:1}
/* QA 2026-09-25: unlit stars were #d6d6d6 (~1.7:1 on white). #8c8c8c clears
   3:1 for the control glyph while still reading as "empty". */
.stars button.lit{color:var(--star)}
@media (hover:hover){
  .stars button:hover{color:var(--star)}
}

.favbtn.on{border-color:var(--ink)}
/* P1: icon-only buttons keep their visual glyph size but get a real hit
   area on touch via min-width/min-height below; inline-flex centers the
   glyph when those minimums kick in. */
.rmfav,.dismiss-intro{display:inline-flex;align-items:center;justify-content:center}
@media (hover:hover){
  .dismiss-intro:hover{color:var(--ink)}
}
.rmfav{border:none;background:none;color:var(--faint);font-size:18px;padding:2px 6px}
@media (hover:hover){
  .rmfav:hover{color:var(--ink)}
}

/* P1: one high-contrast focus ring for every interactive element.
   Specific components may refine it; nothing here removes an outline
   without a replacement. */
:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
/* Skip link, visually hidden until focused. Rendered by render_header
   (site_chrome.py) on secondary pages and in index.html's own header. */
.skip-link{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.skip-link:focus,.skip-link:active{position:fixed;top:12px;left:12px;z-index:200;width:auto;height:auto;margin:0;padding:10px 16px;clip:auto;white-space:normal;background:var(--ink);color:#fff;border-radius:8px;font-weight:700}

/* P1: WCAG 1.4.13-safe custom tooltip (see attachTip in app.js).
   Ignores the pointer so moving over it never dismisses it. */
.tip{
  position:absolute;z-index:60;background:var(--ink);color:#fff;
  font-size:13px;line-height:1.45;padding:6px 10px;border-radius:6px;
  max-width:240px;pointer-events:none;
}

/* P1: honor reduced motion */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  html{scroll-behavior:auto !important}
}

/* ---------- calendar ---------- */

#fav-list{margin-bottom:8px}
.favrow{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line);font-size:15px}
.favrow .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.favrow .rmfav{margin-left:auto}
@media (max-width:480px){
  /* The 5-star touch targets (44px each on coarse pointers) leave no room
     for the title, so it truncated to a few characters. On narrow screens
     the title takes its own line and wraps; stars + remove sit below. */
  .favrow{flex-wrap:wrap;row-gap:8px}
  .favrow .t{flex:1 1 calc(100% - 25px);white-space:normal}
  .favrow .stars{margin-left:25px}
  .favrow .rmfav{margin-left:auto}
}

.cal-head{display:flex;align-items:center;gap:12px;margin:18px 0 10px}
.cal-head h2{margin:0;flex:1}
/* week titles are one-liners by construction; nowrap guarantees the
   Month/Week toggle below never jumps position on narrow screens */
#cal-title{white-space:nowrap}

.cal{
  display:grid;grid-template-columns:repeat(7,1fr);gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:8px;overflow:hidden;
  touch-action:pan-y;
}
.dow{background:var(--wash);font-size:12px;color:var(--muted);padding:6px;text-align:center}
.cal-rowhead{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;background:var(--line);grid-column:1/-1}
/* QC round 2: role="row" wrappers for the calendar week rows (see renderCalendar
   in app.js). Mirrors .cal-rowhead so the 7-column layout is unchanged. */
.cal-row{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;background:var(--line);grid-column:1/-1}
.day{background:#fff;min-height:64px;padding:6px;font-size:13px;overflow:hidden;touch-action:manipulation;cursor:pointer}
.day.blank{background:var(--wash);cursor:default}
.day .num{font-size:12px;color:var(--muted);margin-bottom:2px}
.day.today{background:var(--ywash)}
.day.today .num{font-weight:700;color:var(--ink)}
.day.selected{outline:2px solid var(--ink);outline-offset:-2px}
.day:focus-visible{outline:2px dashed var(--ink);outline-offset:-2px}
.cal-dots{display:flex;gap:4px;align-items:center;justify-content:center;margin-top:6px;flex-wrap:wrap}
.cal-dot{width:7px;height:7px;border-radius:50%;background:var(--c);flex:none}
.cal-more{font-size:11px;color:var(--muted);font-weight:600}
.cal-agenda{margin-top:14px}
.cal-agenda:empty{display:none}
.agenda-h{margin:0 0 6px;font-size:16px}

.cal-svcs{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 0 10px;font-size:14px;color:var(--muted)}
.cal-svcs:empty{display:none}
.cal-leagues{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 10px;font-size:14px;color:var(--muted)}
.cal-leagues[hidden]{display:none}
/* QC 2026-09-25: static league chips are labels, not buttons — wash fill and
   no visible border so they never mimic .chipbtn. */
.leaguechip{display:inline-block;border:1px solid transparent;border-radius:999px;padding:3px 12px;background:var(--wash);font-size:14px;color:var(--ink)}
.svcbadge{display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:999px;padding:3px 12px 3px 10px;color:var(--ink);background:#fff;font-size:14px}
button.svcbadge{font:inherit;cursor:pointer;line-height:1.2;touch-action:manipulation}
.svcbadge[aria-pressed="false"]{border-style:dashed;color:var(--muted)}
/* QA 2026-09-25: the off state used opacity:.45 (14px ink at ~2.88:1 on
   white). Dashed border + muted text (#6f6f6f, 4.83:1) reads as "off"
   without dropping below AA. The brand dot keeps full strength. */

/* ---------- planner ---------- */

.totalbox{border:1px solid var(--ink);border-radius:12px;padding:16px 18px;margin:20px 0;overflow-x:auto;background:var(--ywash)}
.totalbox p{margin:0}
.totalbox .big{font-size:20px;font-weight:700}
/* Calendar tab hero: the twofold value (tracked services + calendar) in one
   glanceable line, wearing the brand yellow wash like .totalbox. */
.cal-hero{background:var(--ywash);border:1px solid var(--ink);border-radius:8px;padding:14px 16px;margin:0 0 16px;font-size:15px;position:relative}
.cal-hero p{margin:0;padding-right:28px}
.cal-hero strong{font-weight:700}
.cal-hero .dismiss-intro{position:absolute;top:4px;right:4px;border:none;background:none;color:var(--faint);font-size:18px}

.scard{border:1px solid var(--line);border-radius:8px;padding:16px 18px;margin:14px 0;background:var(--ywash)}
/* R15: per-service planner cards wear the same light service-color wash as
   their tracked show cards in the catalog (R2); --c is set on the card. */
.scard-svc{background:color-mix(in srgb, var(--c) 9%, #fff)}
/* QA 2026-09-25: secondary copy on the 9% service-color wash renders at
   #545454 (~7.5:1 on white) so it holds AA on every brand tint; --muted
   dips toward 4.5:1 on the more saturated washes. */
.scard-svc .sub,.scard-svc .manage,.scard-svc .scard-prio{color:#545454}
/* R16: bundle cards are neutral light grey, not yellow, not service colors. */
.scard-bundle{background:var(--wash)}
.scard h3{margin:0 0 4px;display:flex;align-items:center;flex-wrap:wrap;row-gap:2px}
.scard .sub{color:var(--muted);font-size:15px;margin:0 0 10px}
.scard .manage{color:var(--muted);font-size:15px;margin:10px 0 0}
/* batch 2: filter group titles, all-shows jump bar, planner priority header */
.filter-group-title{display:block;font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin:16px 0 6px}
.all-shows-jump{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:4px 0 16px;font-size:15px;color:var(--ink)}
.all-shows-jump .jump-label{font-weight:600;margin-right:2px}
.all-shows-jump a{display:inline-block;padding:6px 16px;border:1px solid var(--line);border-radius:999px;background:var(--wash);color:var(--ink);text-decoration:none;font-weight:600;font-size:13px;white-space:nowrap;min-height:44px;line-height:30px}
@media (hover:hover){
  .all-shows-jump a:hover{background:var(--ink);color:#fff;border-color:var(--ink)}
}
.all-shows-jump a:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.sechead{scroll-margin-top:10px}
.scard-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px 12px;margin:0 0 4px}
.scard-header h3{margin:0}
/* QC 2026-09-25: header is two columns (content + toggle). The prio line
   lives inside head-main, stacked under the save line. No flex-wrap or
   order hacks: the old wrapping layout left blank space on mobile when
   the save line + 44px toggle overflowed. */
.scard-head-main{flex:1 1 auto;min-width:0}
/* R6: collapsed header always shows money saved + active months, one line */
.scard-head-main{flex:1 1 auto;min-width:0}
.scard-sum{margin:2px 0 0;font-size:13px;font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.scard-prio{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:var(--muted);white-space:nowrap}
.prio-stars{color:var(--ink);letter-spacing:2px}
/* bundle savings line: deliberately quiet, no box and no pill. The black
   Best-value pill on the winning option is the visual marker. */
.bundle-verdict{font-size:14px;color:var(--muted);margin:10px 0 4px}
/* F10: ad-tier disclosure tag on bundle card titles (ad-free vs ad-supported) */
.tier-tag{display:inline-block;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;padding:2px 9px;border-radius:999px;border:1px solid var(--line);background:var(--wash);white-space:nowrap;vertical-align:middle;margin-left:8px}
/* R4 bundle card redesign: coverage grid, payment-options divider, and
   per-option month strips with demand dots (dots = services with demand
   that month; solid chip = bundle month, outlined = pay-separately month) */
#bundle-check .cov-head{font-size:15px;margin:8px 0 4px}
#bundle-check .cov-grid{list-style:none;margin:0 0 6px;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:5px 14px;font-size:15px}
#bundle-check .cov-grid li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#bundle-check .cov-grid li.zero{color:var(--faint)}
/* phones: single column so service prices never truncate with ellipsis.
   Sits after the 2-column base rule: equal specificity, so later wins. */
@media (max-width:480px){
  #bundle-check .cov-grid{grid-template-columns:1fr}
}
#bundle-check .cov-sub{font-size:14px;color:var(--muted);margin:8px 0 4px}
#bundle-check .opts-label{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin:14px 0 0;border-top:1px solid var(--line);padding-top:10px}
#bundle-check .legend{font-size:13px;color:var(--muted);margin:8px 0 2px}
#bundle-check .opts{margin:2px 0 4px}
#bundle-check .opt{padding:10px 0;border-top:1px solid var(--line)}
#bundle-check .opt:first-child{border-top:0;padding-top:8px}
#bundle-check .opt-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:2px}
#bundle-check .opt.save .opt-name,#bundle-check .opt.save .opt-price{font-weight:700}
#bundle-check .opt-price{white-space:nowrap}
#bundle-check .best-pill{font-size:11px;font-weight:600;background:var(--ink);color:#fff;border-radius:999px;padding:2px 9px;margin-left:8px;white-space:nowrap}
#bundle-check .opts .months{margin:8px 0 6px}
#bundle-check .opts .note{display:block;margin-top:2px}
/* option chips: month label + demand dots; the brand bar is dropped here  - 
   bundles have no single brand, and it overlapped the dots */
#bundle-check .bopts .m{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:6px 0}
#bundle-check .bopts .m.on{box-shadow:none}
#bundle-check .bopts .mlab{line-height:1.2}
/* planner service strips use the same dot treatment (same 8px dots, same
   4px spacing) instead of the old brand-color underline bar */
#planner-list .months .m{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;padding:6px 0}
#planner-list .months .m.on{box-shadow:none}
/* R6 refinement: dormant month cells are plain muted text - no cell outline,
   no hollow dot (that treatment is gone from the per-service grid; bundle
   option chips keep their own D14 styling). Active months keep the filled
   treatment. */
#planner-list .months .m{border-color:transparent;background:transparent;color:var(--muted)}
#planner-list .months .m.on{background:var(--ink);color:#fff;border-color:var(--ink)}
#planner-list .months .mlab{line-height:1.2}
/* demand dots, shared: one 10px brand dot per chip, label stacked above */
.mdots{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;align-content:center;gap:4px;min-height:20px;max-width:100%}
.mdots i{width:10px;height:10px;border-radius:50%;background:var(--c,#999);flex:none}
.m.on .mdots i{box-shadow:0 0 0 1px rgba(255,255,255,.6)}
#bundle-check .m.hollow{background:#fff;color:var(--ink);border-color:var(--ink)}
.tier-tag.ad{background:#edf0f3;border-color:#c9d2da}
.tier-tag.clean{background:#eef7ee;border-color:#bfe0bf}
.tier-tag.mixed{background:#f3ecfd;border-color:#cdbcf0}
/* batch 2: progressive chunking button centers under its section */
.load-more{display:block;margin:14px auto 6px}
.months{display:flex;gap:4px;margin:10px 0}
.m{
  flex:1;text-align:center;font-size:11px;padding:5px 0;
  border:1px solid var(--line);border-radius:6px;color:var(--faint);background:#fff;
}
.m.on{background:var(--ink);color:#fff;border-color:var(--ink)}
.scard .shows{font-size:15px;margin:6px 0}
.scard .money{font-size:15px;margin:8px 0 0}
.scard .money strong{font-weight:700}

.assump{font-size:14px;color:var(--muted);padding-left:20px}
.assump li{margin-bottom:4px}

/* ---------- footer ---------- */

footer{border-top:1px solid var(--line);margin-top:26px;padding:18px 0 44px;font-size:14px;color:var(--muted)}
footer ol{padding-left:20px;margin:0 0 10px}
footer li{margin-bottom:4px}
footer p{margin:6px 0}
footer .footbtn{background:none;border:none;padding:0;font:inherit;color:var(--muted);text-decoration:underline;cursor:pointer}
footer .footbtn:hover{color:var(--ink)}
.footcols{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin:20px 0 6px}
.footcol{border:1px solid var(--line);border-radius:8px;padding:14px 16px;background:var(--wash);text-align:center}
.footcol p{margin:10px 0 0;font-size:13px}
@media (max-width:640px){.footcols{grid-template-columns:1fr}}
.tipthanks{text-align:center;color:var(--muted);font-size:14px;margin:2px 0 16px}

.cal-head{flex-wrap:wrap}
.viewtoggle{display:inline-flex}
.viewtoggle button{border-radius:0;margin-left:-1px}
/* QC 2026-09-25: one segmented-control shape site-wide — the 999px pill
   (matches .seg and the chip language); the 6px end caps were the outlier. */
.viewtoggle button:first-child{border-radius:999px 0 0 999px;margin-left:0}
.viewtoggle button:last-child{border-radius:0 999px 999px 0}
.viewtoggle button.on{background:var(--ink);color:#fff;border-color:var(--ink)}

.weeklist{display:flex;flex-direction:column;gap:10px}
.weekday{border:1px solid var(--line);border-radius:8px;padding:10px 14px;background:#fff}
.weekday.today{background:var(--ywash)}
.weekday-h{font-weight:600;margin-bottom:4px}
.weekep{display:flex;align-items:center;gap:8px;padding:3px 0;font-size:15px}
.binge-wrap{margin:2px 0}
.weekep.binge-row{background:var(--wash);border:1px solid var(--line);border-radius:8px;padding:6px 10px}
.binge-row>span:nth-child(2){flex:1;min-width:0}
.ep-badge{display:inline-block;font-size:12px;color:var(--muted);border:1px solid var(--line);border-radius:999px;padding:1px 8px;white-space:nowrap;background:#fff}
.binge-toggle{font-size:13px;padding:4px 12px;border-radius:999px;border:1px solid var(--line);background:#fff;cursor:pointer;white-space:nowrap}
.binge-toggle:hover{background:var(--line)}
.binge-items{margin:2px 0 8px;padding-left:18px}
.chip.binge-chip{font-weight:600}

/* ---------- small screens ---------- */

@media (max-width:640px){
  /* QC 2026-09-25: stick only the slim tab bar on phones (tabs + Share);
     the brand block scrolls away. Solid background + z-index so scrolled
     content never shows through. Noah 2026-09-25: the persisting bar must
     stay under 15% of the viewport height so content stays visible. */
  .tabbar{position:sticky;top:0;background:var(--bg);z-index:50;max-height:15vh}
  /* Binge-drop rows: the nowrap episode badge can overflow the 200px of title
     space on 375px screens and bleed under the toggle button. Wrap the row so
     the title + badge get their own line and the toggle sits below, right. */
  .weekep.binge-row{flex-wrap:wrap;row-gap:6px}
  .weekep.binge-row>span:nth-child(2){flex:1 1 100%}
  .weekep.binge-row .binge-toggle{margin-left:auto}
  body{font-size:16px}
  header h1{font-size:35px}
  .day{min-height:56px;font-size:11px}
  .dow{font-size:11px;padding:4px 2px}
  /* calendar header: the week title always takes its own full-width row.
     Short titles ("Week of Sep 20") would otherwise share the "Jump to
     today" row while long spanning titles ("Week of Nov 29 - Dec 5")
     drop to a new line, making the Month/Week toggle jump between weeks. */
  .cal-head #cal-title{flex:1 1 100%;font-size:21px}
  .cal-head .viewtoggle{order:6;flex:1 1 100%;display:flex}
  .cal-head .viewtoggle button{flex:1;padding:10px 0}
  /* R27 (Noah, 2026-09-22): prev/next arrows sit directly under the
     Month/Week toggle as a full-width pair of touch-sized buttons. */
  .cal-head .cal-nav-row{order:7;flex:1 1 100%;display:flex;gap:10px}
  .cal-head .cal-nav-row button{flex:1;padding:10px 0;min-height:44px}
  /* planner totals table: shrink type and let long headers wrap so all
     four columns fit a phone screen; .totalbox scrolls as a backstop */
  .totalbox{padding:14px 10px}
  .totalbox table.cost{font-size:13px}
  .totalbox table.cost thead th{font-size:11px}
  .totalbox table.cost thead th.r{white-space:normal}
  /* in-season league chips: one horizontally scrollable row on phones so
     the calendar grid never gets pushed down however many leagues are tracked */
  .cal-leagues{flex-wrap:nowrap;overflow-x:auto;padding-bottom:6px;scrollbar-width:thin}
}

/* ---------- R28 (Noah, 2026-09-22): the hibernate hero's per-service
   breakdown table fills the card on desktop instead of shrink-wrapping to
   its content (which left a wide empty yellow region). Mobile keeps its
   own type-fitting rules below. ---------- */
@media (min-width:641px){
  .totalbox table.cost{width:100%}
}

/* Touch targets: 44px minimum on coarse-pointer (touch) devices per
   WCAG 2.5.8, and at <=480px regardless of pointer (hybrid laptops report
   fine pointers but are still thumb-driven at phone widths). jsdom can't
   measure layout, so this is verified by 375px/393px screenshots, not by
   the smoke suite. */
@media (pointer:coarse),(max-width:480px){
  .chipbtn{min-height:44px}
  nav a{min-height:44px;display:inline-flex;align-items:center}
  .controls select{min-height:44px}
  .stars button{min-width:44px;min-height:44px}
  .binge-toggle{min-height:44px}
  /* P1: star priority buttons, remove buttons, and other icon-only
     controls keep their visual glyph size but get a 44x44 hit area */
  .rmfav,.dismiss-intro{min-width:44px;min-height:44px}
  .scard-toggle{min-width:44px;min-height:44px}
  #share-modal-x,#move-modal-x{min-width:44px;min-height:44px}
  #cal-prev,#cal-next{min-width:44px;min-height:44px}
  #share-open{min-height:44px}
  .svcbadge{min-height:44px}
  /* QC 2026-09-26: waitlist submit buttons (launch band + footer compact)
     meet the 44px touch target on touch / narrow screens. */
  .waitlist-form button[type=submit]{min-height:44px}
  /* QC 2026-09-25: let the save line wrap on touch (the nowrap + ellipsis
     was for desktop one-line truncation). The structural two-column header
     keeps the toggle top-aligned. */
  .scard-sum{white-space:normal}
  /* QA 2026-09-25: track buttons, calendar watchgroup disclosures, and the
     planner window slider were under 44px on touch. */
  .favbtn{min-height:44px}
  .watchgroup-toggle{min-height:44px}
  .sliderwrap input[type=range]{min-height:44px}
  /* QC 2026-09-25: calendar view toggles, jump-to-today, month/year selects,
     and footer utility buttons were under 44px on touch. */
  #view-month,#view-week,#cal-today{min-height:44px}
  #cal-month,#cal-year{min-height:44px}
  /* QC batch 2026-09-25: #sample-clear lives in the demo banner, not a
     footer, so the selector must cover every .footbtn. */
  .footbtn{min-height:44px;display:inline-flex;align-items:center}
  /* QC round 3: the planner cost-detail disclosure summary was ~38px. */
  details.costdetail summary{min-height:44px;display:flex;align-items:center}
}

/* ---------- feedback round: nav, how-it-works, tables, planner ---------- */

/* ---------- R8: lineup chip owns its row, PLATFORM its own line ---------- */
#catalog-filters .filter-row{flex:1 1 100%}
#catalog-filters .filter-group-title{flex:1 1 100%}

/* ---------- R9: bear explainer mini-cards (supersede the R3 strip) ----------
   Slight orange wash on the card background (approved R2 exception); all text
   stays neutral ink. Horizontal layout, bear left / text right, compact for
   mobile. */
#how{display:grid;gap:8px;margin:16px 0 6px}
.home-hero{margin:20px 0 4px;max-width:704px}
.home-hero h2{font-size:26px;margin:0 0 6px;letter-spacing:-.01em}
/* QC 2026-09-25: the solid-amber bar shared the viewport with the solid-amber
   CTA. Demoted to a tinted wash with an amber hairline so the CTA is the
   single solid-amber element (yellow hierarchy rule). */
.home-hero h2::after{content:"";display:block;width:51px;height:4px;background:var(--ywash);border-radius:2px;margin-top:8px}
.home-hero p{margin:0 0 12px;font-size:16px}
.home-cta{display:inline-block;background:var(--amber);color:#1a1a1a;font-weight:700;padding:9px 20px;border-radius:8px;text-decoration:none}
.home-cta:hover{background:color-mix(in srgb, var(--amber) 82%, #000);color:#1a1a1a}
#how .howto{display:flex;gap:10px;align-items:center;border:1px solid var(--line);border-radius:8px;padding:10px 12px;background:var(--ywash)}
#how .howto p{margin:0;font-size:14px}
#how .bear--howto{width:44px;height:44px;flex:none}

.sechead{font-size:var(--text-h2);margin:26px 0 10px}
.sechead:first-child{margin-top:6px}

.watchgroup{font-size:17px;margin:22px 0 4px}
.watchgroup:first-child{margin-top:6px}
/* R27 (Noah, 2026-09-22): calendar watchgroups (leagues / airing / queued)
   are collapsed disclosures — only the label + count shows until expanded. */
.watchgroup-toggle{display:flex;align-items:center;gap:0;width:100%;padding:0;border:0;background:none;
  font:inherit;font-size:17px;font-weight:700;color:var(--ink);cursor:pointer;text-align:left;margin:22px 0 4px}
.watchgroup-toggle .wg-count{color:var(--muted);font-weight:600}
.watchgroup-toggle .wg-caret{margin-left:auto;color:var(--muted);font-size:20px;line-height:1;display:inline-block;transition:transform .15s}
.watchgroup-toggle[aria-expanded="true"] .wg-caret{transform:rotate(90deg)}
.watchgroup-body{margin:0 0 4px}

table.cost{border-collapse:collapse;margin:10px 0;font-size:15px;min-width:min(100%,340px)}
table.cost td,table.cost th{padding:5px 10px 5px 0;text-align:left;vertical-align:top}
table.cost .r{text-align:right;padding-right:0;white-space:nowrap}
table.cost thead th{font-size:13px;color:var(--muted);font-weight:600;border-bottom:1px solid var(--line)}
table.cost tr.total td{border-top:1px solid var(--line);padding-top:8px}
table.cost tr.save td{font-weight:600}

/* planner mobile layout: .r zeroes right padding for edge alignment, so
   restore the inter-column gap on the left of right-aligned cells
   (headers AND data cells, or adjacent columns run together) */
table.cost th.r,table.cost td.r{padding-left:10px}
/* streamer names stay on one line inside the totals box */
.totalbox table.cost td:first-child{white-space:nowrap}

/* planner month blocks: 3-letter labels; active months carry one brand dot
   (shared dot style with the bundle strips), not the old underline bar */
.m{font-size:11px;letter-spacing:.2px}
.m.on{background:var(--ink);color:#fff;border-color:var(--ink)}

/* month strip: wrap to two lines (six per row) when the planner window
   exceeds 6 months. Chips never grow: a short final row stays left-aligned
   at the same chip size instead of stretching to fill the row. */
.months.wrap2{flex-wrap:wrap}
.months.wrap2 .m{flex:0 1 calc(16.666% - 6px)}

.sliderwrap{display:inline-flex;align-items:center;gap:8px;font-size:14px;color:var(--muted)}
.sliderwrap input[type=range]{width:130px;accent-color:var(--ink)}
/* thin divider between the pricing-basis toggle and the ad-tier toggle */
#planner-summary .controls .ctl-sep{width:1px;background:var(--line);margin:2px 8px;align-self:stretch}
/* subtle fallback note when a service has no ad-supported tier */
#planner-list .tier-fallback{margin:0 0 6px;font-size:13px}
.sliderwrap strong{color:var(--ink);min-width:44px}

.intro .dismiss-intro{font-size:16px}

.cal-head select{font:inherit;padding:4px 8px;border:1px solid var(--line);border-radius:6px;background:#fff}

/* ---------- bear illustration system (wiring spec v1.1) ---------- */
.bear{width:auto;flex:none}
#site-name{display:flex;align-items:center;gap:10px}
.bear--sitemark{height:55px}
.bear--bearline{height:28px;vertical-align:-5px;margin-right:10px}
.bear--corrections{height:25px;vertical-align:-4px;margin-right:8px}
.bear--footcol{height:80px}
.bear--watchgroup{height:50px;vertical-align:middle;margin-right:12px}
.bear--sechead{height:50px;vertical-align:middle;margin-right:12px}
.bear--load{height:50px;vertical-align:middle;margin-right:10px}
.bear--empty{display:block;margin:8px auto 12px}
.bear--empty-96{height:120px}
.bear--empty-120{height:150px}
.bear--sumhead{height:80px;float:left;margin:4px 14px 10px 0}
/* NOTE: .bear--sumhead lives as first child of .totalbox (see app.js renderPlanner),
   NOT #planner-summary: #planner-summary receives intro/slider content before the
   blank-slate early return, so anchoring there would leak the bear onto the empty
   state. .totalbox is only built after the return, so the bear hides naturally. */
.bear--sub{height:40px;vertical-align:-8px;margin-right:8px}
.bear--h3-48{height:60px;vertical-align:middle;margin-right:12px}
.bear--h3-64{height:80px;vertical-align:middle;margin-right:12px}
.bear--h3-40{height:50px;vertical-align:middle;margin-right:12px}
.bear--manage{height:25px;vertical-align:-4px;margin-right:8px}
/* star instruction bar - bear-free by design (mockup v2) */
#fav-note.starbar{display:flex;gap:12px;align-items:flex-start;border:1px solid var(--line);
  border-radius:12px;padding:14px 16px;background:#fff;color:var(--ink);font-size:15px}
#fav-note .star{flex:none;font-size:24px;line-height:1.4}

/* ---------- shareable URLs: header button, dialog, shared view ---------- */
.sharebtn{margin-left:auto;display:inline-flex;align-items:center;gap:5px;font-size:15px;padding:3px 10px}
/* R27 (Noah, 2026-09-22): the whole top nav — three numbered tabs plus the
   Share button — stays on one horizontal line at mobile widths. Tabs take
   their natural width with one uniform 8px gap (R27 spacing fix); Share parks
   right via margin-left:auto. Supersedes the R19 judgment call that let
   Share sit on its own row, and the R23 flex:1 equal-boxes layout. */
@media (max-width:480px){
  nav{flex-wrap:nowrap;gap:8px;align-items:center;overflow-x:auto}
  /* R27 (Noah, 2026-09-22): tabs take their natural width with one uniform
     8px gap instead of flex:1 centering — centered equal boxes left visibly
     more whitespace around the short "Save" label. Share parks right via
     margin-left:auto. */
  nav a{flex:0 1 auto;min-width:0;white-space:nowrap;font-size:15px}
  nav a .tabnum{flex:0 0 auto;width:18px;height:18px;font-size:11px;margin-right:4px}
  .sharebtn{margin-left:auto;flex:0 0 auto;white-space:nowrap;font-size:15px;padding:3px 8px}
}
dialog#share-modal{border:1px solid var(--line);border-radius:12px;padding:0;
  max-width:min(92vw,460px);width:100%;color:var(--ink)}
dialog#share-modal::backdrop{background:rgba(0,0,0,.35)}
.modal-card{padding:18px 20px}
.modal-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}
.modal-head h2{margin:0;font-size:20px}
.modal-body p{margin:0 0 10px;font-size:15px}
.share-link-row{display:flex;gap:8px;margin-top:12px}
.share-link-row input{flex:1;min-width:0;font:inherit;padding:6px 10px;
  border:1px solid var(--line);border-radius:6px;color:var(--ink)}
.shared-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:14px 0}
.shared-row{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid var(--line)}
.show-details{display:flex;align-items:center;min-width:0;flex:1}
.show-details .t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.interaction-zone{display:flex;flex-direction:column;align-items:flex-end;gap:8px;flex:none}
.sender-stars{font-size:13px;color:var(--muted);white-space:nowrap}
.sender-stars .label{margin-right:6px}
.add-control{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}
.inert-pill{font-size:13px;color:var(--muted);border:1px dashed var(--line);border-radius:999px;padding:4px 12px;white-space:nowrap}
@media (max-width:480px){
  .shared-row{flex-direction:column;align-items:flex-start}
  .interaction-zone{align-items:flex-start;width:100%}
  .add-control{justify-content:flex-start}
}
.shared-rank{letter-spacing:2px;white-space:nowrap;font-size:14px}
/* tight wrapping service color key (non-interactive; calendar filter badges keep their own role) */
.service-key{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:13px;color:var(--muted);margin:2px 0 12px}
.service-key>span{display:inline-flex;align-items:center;white-space:nowrap}
/* share dialog virality block */
.nn-head{margin:18px 0 4px;font-size:17px}
.nn-text{white-space:pre-wrap;background:var(--wash);border:1px solid var(--line);border-radius:8px;padding:10px 12px;font-size:14px;margin:8px 0;max-width:var(--measure)}
/* R20: the preview renders the copied lines verbatim, so no star-column
   spans are needed anymore (the old .nn-row/.nn-stars fixed-width hack is
   gone with the stars-first format). */
.nn-line{margin:2px 0}
.microcopy{font-size:12px;color:var(--faint)}
.toast{position:fixed;left:50%;bottom:24px;transform:translateX(-50%) translateY(16px);
  background:var(--ink);color:#fff;font-size:14px;padding:10px 18px;border-radius:999px;
  opacity:0;pointer-events:none;transition:opacity .25s,transform .25s;z-index:50;
  max-width:min(92vw,560px);text-align:center}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.card.pulse{animation:cardPulse 2s ease-in-out}
@keyframes cardPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(180,83,9,0)}
  25%,75%{box-shadow:0 0 0 4px rgba(180,83,9,.55)}
  50%{box-shadow:0 0 0 7px rgba(180,83,9,.25)}
}
/* ---------- contact ---------- */

.homelink{color:inherit;text-decoration:none}
.contact-form{max-width:56ch;display:grid;gap:14px;margin:18px 0 26px}
.contact-form label{display:grid;gap:6px;font-weight:600}
.contact-form input[type=text],
.contact-form input[type=email],
.contact-form select,
.contact-form textarea{font:inherit;font-weight:400;padding:8px 12px;border:1px solid var(--line);border-radius:6px;background:#fff;width:100%}
.contact-form textarea{resize:vertical}
.contact-form .hp{position:absolute;left:-9999px;opacity:0;height:0;width:0}
.waitlist-form .hp{position:absolute;left:-9999px;opacity:0;height:0;width:0}
.contact-form button{font-weight:600;padding:10px 22px;border-radius:999px;border:1px solid var(--ink);background:var(--ink);color:#fff;justify-self:start}
@media (hover:hover){
  .contact-form button:hover{background:#000;border-color:#000}
}
.form-note{color:var(--muted);font-size:15px;min-height:1.6em}

/* ---------- waitlist (launch infra) ---------- */
/* Amber is the brand focal: the band is a bordered card on --wash, and the
   primary CTA carries the amber button treatment (btn-primary). */
.waitlist-band{margin:26px 0 34px;padding:26px 24px;border:1px solid var(--line);border-radius:12px;background:var(--wash);text-align:center}
.waitlist-band h2{margin:0 0 8px}
.waitlist-band .sec-sub{margin:0 auto 16px;max-width:var(--measure)}
.waitlist-form{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;align-items:center}
.waitlist-form input[type=email]{font:inherit;padding:10px 14px;border:1px solid var(--line);border-radius:999px;background:#fff;min-width:16em}
.waitlist-form .form-note{flex-basis:100%;margin:0}
.waitlist-compact{display:grid;gap:8px;justify-items:center;margin-top:10px}
.waitlist-compact label{display:grid;gap:6px;font-weight:600;font-size:13px}
.waitlist-compact input[type=email]{font:inherit;padding:8px 12px;border:1px solid var(--line);border-radius:6px;background:#fff;width:100%}
.waitlist-compact .form-note{font-size:13px}

/* ---------- cancellation guides ---------- */
.guide{max-width:68ch}
.guide h1{font-size:30px;line-height:1.2;margin:6px 0 14px}
/* Brand focal: the guide/pricing h1 carries a dark-gold underline, tying
   every article page to the amber hierarchy (Option A, 2026-09-25). */
.guide h1{border-bottom:3px solid var(--amber-deep);padding-bottom:10px}
/* Yellow-wash hero for hub pages (guides, contact, pricing): the page title
   sits on the brand wash, mirroring the planner .totalbox treatment. */
.page-hero{background:var(--ywash);border:1px solid var(--ink);border-radius:12px;padding:18px 20px;margin:14px 0 18px}
.page-hero h1{font-size:30px;line-height:1.2;margin:0 0 8px}
.page-hero h1{margin:0 0 6px}
.guide h2{font-size:var(--text-h2);margin:26px 0 10px}
.guide p,.guide li{font-size:16px;line-height:1.55}
.guide-cta{background:var(--wash);border:1px solid var(--line);border-radius:12px;padding:14px 18px}
.guide-index{list-style:none;margin:18px 0;padding:0;display:grid;gap:10px}
.guide-index li{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.guide-meta{color:var(--muted);font-size:14px}
/* pricing pages: plan comparison tables scroll horizontally on small screens */
.table-scroll{overflow-x:auto;margin:10px 0}
table.plans{border-collapse:collapse;font-size:15px;min-width:680px;width:100%}
table.plans th,table.plans td{padding:8px 12px 8px 0;text-align:left;vertical-align:top;border-bottom:1px solid var(--line);white-space:nowrap}
table.plans th{font-size:13px;color:var(--muted);font-weight:600}
table.plans td.notes{white-space:normal;min-width:180px}
table.plans td small{color:var(--muted)}
@media (max-width:480px){table.plans{font-size:13px}}

/* P2: sample lineups. Dashed box in the empty states; quiet one-line
   banner while a demo is active. */
.sample-cta{border:1px dashed var(--line);border-radius:8px;background:var(--wash);padding:14px 16px;margin:14px 0}
.sample-cta p{margin:8px 0}
.sample-cta .chipbtn{margin:4px 8px 4px 0}
.sample-demo .footbtn{font-size:inherit}
/* R17: numbered nav tabs replace the first-session stepper (removed). The
   number badge teaches the 1-2-3 flow permanently; the active tab's badge
   fills amber to match the active underline. */
nav a .tabnum{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:var(--wash);border:1px solid var(--line);font-size:12px;font-weight:700;color:var(--muted);margin-right:6px;vertical-align:1px}
nav a.active .tabnum{background:var(--accent);border-color:var(--accent);color:#fff}
/* ---------- sports expansion (v1) ---------- */
/* [TV Shows | Sports] segmented add flow: joined pills, one active */
.seg{display:inline-flex;border:1px solid var(--line);border-radius:999px;overflow:hidden}
.seg .chipbtn{border:0;border-radius:0;background:transparent}
.seg .chipbtn + .chipbtn{border-left:1px solid var(--line)}
.seg .chipbtn.on{background:var(--ink);color:#fff}
/* planner toggle groups: visible label above each segmented control so a
   new user can tell what each switch does (aria-labels alone are invisible) */
.ctl-group{display:inline-flex;flex-direction:column;gap:6px}
.ctl-label{font-size:13px;color:var(--muted)}
/* league cards carry a Sport chip instead of a service brand dot */
.tracked-note{font-size:14px;color:var(--muted);margin-right:8px}
/* planner: genuine coverage gaps per followed league */
.gaps-block{margin:26px 0;padding:16px 18px;border:1px solid var(--line);border-radius:12px;background:#fff}
.gaps-block h3{margin:0 0 10px}
.gaps-league{margin:12px 0}
.gaps-league h4{margin:0 0 4px}
.gaps-league ul{margin:6px 0;padding-left:20px}
.gaps-league p{margin:6px 0}

/* ---------- design refresh D1–D21 (2026-09-22), revised R1/R2/R27 ---------- */
/* Yellow hierarchy (Noah's standing rule): solid --amber marks the single most
   important action on a page (primary CTA fills, the active tab underline).
   The pale --ywash is the utility wash: page heroes, notice boxes, the header
   share button. Never solid amber for a utility, never wash for the primary
   CTA. No colored text on show cards. */
.totalbox .big{color:var(--ink)}
.btn-primary{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.btn-primary:hover{background:color-mix(in srgb, var(--accent) 80%, #000);border-color:color-mix(in srgb, var(--accent) 80%, #000);color:#fff}
/* R27: share-flow buttons use the pale-yellow --ywash (the same wash as the
   three bear explainer cards), dark ink text (13.2:1 on the wash, WCAG AA).
   Scoped to the share buttons only. */
#share-open.btn-primary,#share-copy.btn-primary{background:var(--ywash);border-color:var(--line);color:var(--ink)}
#share-open.btn-primary:hover,#share-copy.btn-primary:hover{background:color-mix(in srgb, var(--amber) 24%, #fff);border-color:var(--line);color:var(--ink)}
/* R27 (Noah, 2026-09-22): the planner "Download reminders" (.ics) button is
   black, not amber. */
.icsbtn.btn-primary{background:var(--ink);border-color:var(--ink);color:#fff}
.icsbtn.btn-primary:hover{background:#000;border-color:#000;color:#fff}
/* R2: tracked cards get a subtle service-color wash (~9%); untracked stay white.
   --c is set on the article; the .dot inherits it. */
.card.tracked{background:color-mix(in srgb, var(--c) 9%, #fff)}
/* QA 2026-09-25: same wash treatment as .scard-svc above; the schedule
   disclosure copy darkens to hold AA on the tint. */
.card.tracked details.sched,.card.tracked details.sched summary{color:#545454}
/* D5: tighter card - next line and actions share one row */
/* R1: the row wraps so the 5×44px star row + remove button can never spill
   past the card padding at any viewport width. */
.card .nextrow{display:flex;align-items:center;gap:12px;margin:8px 0;flex-wrap:wrap;min-width:0}
.card .nextrow .next{flex:1 1 160px;min-width:0}
.card .nextrow .actions{margin-top:0;margin-left:auto;min-width:0;max-width:100%}
/* D6: single inline star row, vertically centered in the actions row */
.card .actions .stars{align-self:center}
/* D7: schedule notes behind a disclosure */
.card details.sched{margin:8px 0 0;font-size:13px;color:var(--faint)}
.card details.sched summary{cursor:pointer;color:var(--muted);padding:8px 0;list-style:none;display:flex;align-items:center;gap:8px}
.card details.sched summary::-webkit-details-marker{display:none}
/* QC 2026-09-25 (M17): the chevron is now a shared <span class="chev"> in the
   summary (app.js), styled like the scard toggle — CSS-drawn ::after gone. */
/* Popular-card accolade list: tight, one label per line, no bullets — reads
   clean at phone width and doesn't sprawl on desktop. */
.card details.sched ul{margin:4px 0 10px;padding:0;list-style:none}
.card details.sched li{margin:3px 0}
/* D9: fixed 24px visual star grid, 44px tap targets */
.stars button{font-size:24px;min-width:44px;min-height:44px;padding:0;display:inline-flex;align-items:center;justify-content:center;line-height:1}
/* D10: active-filter count badge on the collapsed Filter & Sort button */
.filter-badge{display:inline-block;min-width:22px;text-align:center;background:var(--accent);color:#fff;border-radius:999px;font-size:12px;font-weight:700;padding:2px 6px;margin-left:6px;vertical-align:1px}
/* D11: per-service planner rows collapse with a chevron */
.scard-toggle{margin-left:auto;flex:none}
.scard-toggle .chev{display:inline-block;transition:transform .15s;font-size:20px;line-height:1;color:var(--muted)}
.scard-toggle[aria-expanded="true"] .chev{transform:rotate(90deg)}
.scard-body[hidden]{display:none}
details.costdetail{margin-top:12px}
details.costdetail summary{cursor:pointer;color:var(--muted);padding:8px 0;font-size:14px;list-style:none;display:flex;align-items:center;gap:8px}
details.costdetail summary::-webkit-details-marker{display:none}
/* shared disclosure chevron spec (see M17 note above) */
details summary .chev{display:inline-block;transition:transform .15s;font-size:20px;line-height:1;color:var(--muted);flex:none}
details[open] summary .chev{transform:rotate(90deg)}
/* D14: outlined hibernate dots, 2px stroke minimum */
.mdots i.off{background:transparent;border:2px solid var(--c,#999);width:10px;height:10px;box-sizing:border-box}
/* D8: share modal friend nudge */
.share-nudge{color:var(--muted);font-size:14px;margin-top:10px}

/* ---------- QC 2026-09-25 (Wave 2): chart type scale, tap targets, link identity ----------
   ph-* overrides live here, NOT in build_price_history.py, so the generator
   stays geometry-only. price-history.html links this stylesheet BEFORE its
   generated <style> block, so overrides are body-qualified to outrank it. */

/* 1. Chart mobile type scale (matches the generator's max-width:560px query).
   Hierarchy: foot 18 < ytick/year/launchlab/ann 24 < rowlab 24 / price 26 <
   pct 28 < main 30. .ph-ann-main is pinned back to 30px after the .ph-ann
   rule (it carries both classes). */
@media (max-width:560px){
  body .ph-hero svg text.ph-ann{font-size:24px}
  body .ph-hero svg text.ph-ytick{font-size:24px}
  body .ph-hero svg text.ph-year{font-size:24px}
  body .ph-hero svg text.ph-launchlab{font-size:24px}
  body .ph-hero svg text.ph-ann-main{font-size:30px}
  body .ph-slope-wrap svg text.ph-pct{font-size:28px}
  body .ph-slope-wrap svg text.ph-rowlab{font-size:24px}
  body .ph-slope-wrap svg text.ph-price{font-size:26px}
  body .ph-slope-wrap svg text.ph-slope-foot{font-size:18px}
}
/* 5. ph-chip focus ring: the generator's off-brand blue #1a73e8 becomes the
   standard 3px solid ink ring. */
body .ph-ctl:focus-visible+.ph-chip{outline:3px solid var(--ink);outline-offset:2px}
/* 3. ph footnote refs: 44px tap target; the generator's text-decoration:none
   is overridden back to an underline (it strips the only link cue). */
body a.ph-fnref{display:inline-block;padding:.5em .65em;min-height:44px;text-decoration:underline}
/* 3. receipts source table (price-history): 44px tap targets on cell links. */
table.receipts td a{display:inline-block;padding:.55em .8em;min-height:44px}

/* 3. 44px tap-target sweep: guide/pricing index lists, in-text links,
   footer note clusters, contact submit. (The pricing index list reuses
   ul.guide-index markup, so the first rule covers it — no duplicate.) */
ul.guide-index li a{display:inline-flex;align-items:center;min-height:44px}
.guide p a,.guide li a,.guide-meta a{display:inline-block;padding:.4em .3em;min-height:44px}
footer p.note a{display:inline-block;padding:.55em .4em}
.contact-form button{min-height:44px}

/* 4. Link identity: body-copy links wear dark gold, underline kept.
   Index lists stay neutral ink (chrome, not body copy). */
.guide p:not(.guide-cta) a,.guide li a{color:var(--amber-deep)}
.guide .guide-index a{color:var(--ink)}

/* 5. Subtle hover feedback for interactive elements that had none. */
@media (hover:hover){
  .day:not(.blank):hover{background:var(--wash)}
  .day.today:hover{background:color-mix(in srgb, var(--amber) 20%, #fff)}
  .watchgroup-toggle:hover .wg-caret{color:var(--ink)}
  .favbtn:hover{background:var(--wash)}
  .viewtoggle button:not(.on):hover{background:var(--wash)}
  .scard-toggle:hover{border-color:var(--ink)}
  .chipbtn:not(.on):hover{background:var(--wash);border-color:var(--faint)}
  button.svcbadge:hover{background:var(--wash)}
  body .ph-chip:hover{border-color:var(--ink)}
}

/* 6. Dormant rebrand (2026-09-26): TM superscript wordmark, trademark
   attribution fine print, and the temporary rebrand continuity note. */
.tm{font-size:.58em;vertical-align:.42em;letter-spacing:0;line-height:0}
.tm-attrib{font-size:12.5px}
.rebrand-note{background:var(--wash);border:1px solid var(--faint);border-radius:10px;
  padding:.6em 1em;margin:0 0 1em;
  font-size:14px;color:var(--muted);text-align:center}
.rebrand-note strong{color:var(--ink)}
