/* 🚩 THE HIDDEN ATTRIBUTE, FIRST, BEFORE ANYTHING ELSE CAN BREAK IT.
   The browser's own rule is `[hidden]{display:none}`, which is a plain type
   selector and therefore loses to ANY class rule that sets display - and this
   file is full of them (`.field{display:grid}`, `.rest{display:flex}`). The
   result is an element that Django, or the script, has marked hidden and that
   the man can still see.
   It has bitten twice: a dead rest-timer button for anyone without JavaScript,
   and - the one Jay screenshotted on 27 Sep - a "What's it called?" box
   sitting under the exercise picker with a normal lift selected, because the
   script had set .hidden = true and the stylesheet ignored it.
   !important is the right tool here. `hidden` is not a style, it is the author
   saying the element is not part of the page yet. Nothing should outvote it.
*/
[hidden]{display:none !important}

/* GymBrosUK design system
   Palette is locked to the client's brief: pure black and cool slate greys only.
   #1E293B / #334155 / #64748B, high-contrast white text, no warm accents.
   The look is soft panels and cards - not the hard brutalist edges of the first pass. */

:root{
  --black:#05070A;
  --bg:#080B0F;
  --bg-2:#0C1116;
  --panel:#111820;
  --panel-2:#151D26;
  --panel-hi:#1E293B;
  --line:rgba(148,163,184,.13);
  --line-2:rgba(148,163,184,.22);
  --slate-700:#334155;
  /* 🚩 Was #64748B. Measured on his phone it came out at 3.57-4.14 against the
     four surfaces we actually use - under the 4.5 floor for body text on every
     one of them, which is why he said it does not read well. #79879D clears it
     everywhere (4.67 worst case) and is still grey, not silver. The old value
     lives on as --slate-600 for the things that are decoration rather than
     words: hairlines, the quiet end of a gradient. */
  --slate-600:#64748B;
  --slate-500:#79879D;
  --slate-400:#8B99AE;
  --slate-300:#94A3B8;
  --slate-200:#CBD5E1;
  --white:#FFFFFF;

  /* His accent, sampled off the mockup he sent (#6C84A8 at the glyph cores) and
     lifted a little so it holds up as text on black. It is a cooler, lighter
     slate rather than a brand blue - close enough to the palette in his vision
     board that the page still reads monochrome, different enough to point at
     one word. Used on the last word of the headline, the pillar subtitles and
     the step numbers. Nowhere else, or it stops meaning anything. */
  --accent:#8CA5C9;
  --accent-dim:#6C84A8;

  --r-sm:10px;
  --r:14px;
  --r-lg:20px;
  --r-xl:28px;

  --shadow:0 1px 0 rgba(255,255,255,.04) inset, 0 18px 40px -24px rgba(0,0,0,.9);
  --shadow-lift:0 1px 0 rgba(255,255,255,.06) inset, 0 30px 60px -30px rgba(0,0,0,1);

  --display:'Archivo',system-ui,sans-serif;
  --body:'Manrope',system-ui,sans-serif;
  --gut:clamp(18px,4vw,52px);
  --maxw:1240px;
}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{
  background:var(--bg);color:var(--white);
  font-family:var(--body);font-size:16px;line-height:1.62;font-weight:400;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}

h1,h2,h3,h4{font-family:var(--display);font-weight:800;letter-spacing:-.025em;line-height:1.08}
h1{font-size:clamp(38px,5.6vw,68px)}
h2{font-size:clamp(28px,3.6vw,44px)}
h3{font-size:clamp(19px,1.9vw,24px);letter-spacing:-.015em}
p{color:var(--slate-300)}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gut)}
.narrow{max-width:820px}
.eyebrow{
  font-size:11.5px;font-weight:800;letter-spacing:.18em;text-transform:uppercase;
  color:var(--slate-500);
}
.muted{color:var(--slate-500)}
.dim{color:var(--slate-300)}

/* ---------- panels ---------- */
.panel{
  background:linear-gradient(180deg,var(--panel-2),var(--panel));
  border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow);
}
.panel-pad{padding:clamp(20px,2.4vw,30px)}
.panel-head{
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;row-gap:6px;
  padding:18px clamp(20px,2.4vw,26px);border-bottom:1px solid var(--line);
}
.panel-head h3{font-size:17px;letter-spacing:-.01em}
.panel-head .more{margin-left:auto;font-size:13.5px;color:var(--slate-400);font-weight:600}
.panel-head .more:hover{color:var(--white)}
.panel-body{padding:clamp(18px,2.2vw,26px)}

.card{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  padding:clamp(18px,2vw,24px);transition:transform .22s cubic-bezier(.2,.7,.3,1),border-color .22s,background .22s;
}
.card:hover{transform:translateY(-3px);border-color:var(--line-2);background:var(--panel-2)}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-weight:700;font-size:15px;letter-spacing:.005em;
  padding:12px 22px;border-radius:999px;border:1px solid transparent;cursor:pointer;
  /* A label long enough to wrap - the pre-launch call to action does on a
     phone - otherwise sets its second line hard left inside a centred pill. */
  text-align:center;
  transition:transform .18s cubic-bezier(.2,.7,.3,1),background .2s,border-color .2s,color .2s,opacity .2s;
}
.btn:hover{transform:translateY(-2px)}
.btn-primary{background:var(--white);color:#0A0E13}
.btn-primary:hover{background:#E9EEF5}
.btn-ghost{border-color:var(--line-2);color:var(--white);background:rgba(148,163,184,.05)}
.btn-ghost:hover{border-color:var(--slate-500);background:rgba(148,163,184,.1)}
.btn-quiet{background:var(--panel-hi);color:var(--white)}
.btn-quiet:hover{background:#27364B}
.btn-sm{padding:9px 16px;font-size:13.5px}
.btn-block{width:100%}
.btn[disabled],.btn.is-disabled{opacity:.45;pointer-events:none}

/* ---------- pills & meta ---------- */
.pill{
  display:inline-flex;align-items:center;gap:7px;
  font-size:12.5px;font-weight:700;letter-spacing:.02em;
  padding:6px 12px;border-radius:999px;
  background:rgba(148,163,184,.1);border:1px solid var(--line);color:var(--slate-200);
}
.pill-quiet{background:transparent;color:var(--slate-500)}
.meta{font-size:13px;color:var(--slate-500)}

/* score chip - Crew Finder fit, never called a "match" */
.score{
  display:inline-flex;flex-direction:column;align-items:center;justify-content:center;
  min-width:56px;padding:8px 10px;border-radius:var(--r-sm);
  background:var(--panel-hi);border:1px solid var(--line-2);
}
.score b{font-family:var(--display);font-size:19px;line-height:1;font-weight:800}
.score span{font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--slate-400);margin-top:3px}

/* ---------- avatars ---------- */
.avatar{
  width:44px;height:44px;border-radius:50%;flex:none;overflow:hidden;
  background:linear-gradient(145deg,var(--panel-hi),var(--slate-700));
  border:1px solid var(--line-2);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--display);font-weight:800;font-size:15px;color:var(--slate-200);
  letter-spacing:.02em;
}
.avatar img{width:100%;height:100%;object-fit:cover}
.avatar-lg{width:64px;height:64px;font-size:20px}
.avatar-sm{width:32px;height:32px;font-size:12px}
.avatar-stack{display:flex}
.avatar-stack .avatar{margin-left:-11px;border:2px solid var(--panel)}
.avatar-stack .avatar:first-child{margin-left:0}

/* ---------- top bar ---------- */
.topbar{
  position:sticky;top:0;z-index:200;
  background:rgba(8,11,15,.78);backdrop-filter:blur(16px);
  border-bottom:1px solid var(--line);
}
.topbar .inner{display:flex;align-items:center;gap:14px;height:70px}
.brand{display:flex;align-items:center;gap:11px;font-family:var(--display);font-weight:800;letter-spacing:-.02em}
.brand .mark{
  width:36px;height:36px;border-radius:10px;background:var(--white);color:#080B0F;
  display:flex;align-items:center;justify-content:center;font-size:13px;letter-spacing:-.03em;
}
.brand .name{font-size:17px}
.nav{display:flex;align-items:center;gap:2px;margin-left:auto}
.nav a{
  padding:9px 13px;border-radius:999px;font-size:14.5px;font-weight:600;color:var(--slate-300);
  transition:color .18s,background .18s;
  /* 🚩 Six items now. Without this the header wraps onto two lines on a laptop
     the moment a seventh word appears - which is exactly what adding "How it
     works" did. Let it be tight rather than let it wrap. */
  white-space:nowrap;
}
@media(min-width:1061px) and (max-width:1240px){
  .nav a{padding:9px 9px;font-size:13.5px}
}
.nav a:hover{color:var(--white);background:rgba(148,163,184,.08)}
.nav a.active{color:var(--white);background:rgba(148,163,184,.13)}
.topbar .actions{display:flex;align-items:center;gap:10px;margin-left:14px}
.iconbtn{
  width:38px;height:38px;border-radius:50%;border:1px solid var(--line);background:var(--panel);
  display:flex;align-items:center;justify-content:center;position:relative;cursor:pointer;
  transition:border-color .2s,background .2s;
}
.iconbtn:hover{border-color:var(--line-2);background:var(--panel-2)}
.iconbtn .dot{
  position:absolute;top:7px;right:8px;width:7px;height:7px;border-radius:50%;
  background:var(--white);border:2px solid var(--panel);
}
.burger{display:none;background:none;border:0;cursor:pointer;padding:8px;margin-left:auto}
.burger span{display:block;width:22px;height:2px;background:var(--white);margin:4px 0;border-radius:2px}

/* ---------- app shell (sidebar pages) ---------- */
.shell{display:grid;grid-template-columns:250px 1fr;gap:clamp(16px,2vw,26px);padding:clamp(20px,2.6vw,32px) 0}
/* 🚩 NOT sticky any more. It was `position:sticky;top:92px`, which meant the
   menu sat dead still for the whole page and then, the moment the shell ran
   out above the footer, shot upwards - Jay's words: "doesn't seem to scroll
   seamlessly with the rest of the page until at the bottom". Measured: pinned
   at 92 from scrollY 0 to 3600, then 92 -> -89 -> -278 in two frames.

   Sticky also hid the bottom of the menu on a shorter window. The panel is
   508px tall; on a 560px viewport there are only 468px below the header, so
   "Account settings" and "Log out" sat off screen and no amount of scrolling
   could reach them - a sticky element pins its TOP, so its overflow is
   unreachable by definition.

   Nothing is lost by letting it scroll: the top bar IS sticky and carries the
   same navigation, so the menu is always a glance away regardless. */
.side{align-self:start}
.side nav{display:grid;gap:3px}
.side nav a{
  display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:12px;
  font-size:14.5px;font-weight:600;color:var(--slate-300);transition:background .18s,color .18s;
}
/* Log out is a form, not a link: Django's LogoutView is POST-only, so an
   anchor pointing at it answers 405 Method Not Allowed. It rides on the same
   selector as the links so the menu still looks like one list. */
.side nav a,.side nav .out button{
  display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:12px;
  font-size:14.5px;font-weight:600;color:var(--slate-300);transition:background .18s,color .18s;
}
.side nav .out{display:contents}
.side nav .out button{
  width:100%;background:none;border:0;font-family:inherit;text-align:left;cursor:pointer;
}
.side nav a:hover,.side nav .out button:hover{background:rgba(148,163,184,.07);color:var(--white)}
.side nav a.active{background:var(--panel-hi);color:var(--white)}
.side .sect{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--slate-700);padding:16px 14px 8px;font-weight:800}
.side .ico{width:18px;height:18px;flex:none;opacity:.85}

.page-head{display:flex;align-items:flex-end;gap:18px;margin-bottom:22px;flex-wrap:wrap}
.page-head h1{font-size:clamp(26px,3vw,36px)}
.page-head .sub{color:var(--slate-500);font-size:14.5px;margin-top:6px}
.page-head .right{margin-left:auto;display:flex;gap:10px}

.grid{display:grid;gap:clamp(14px,1.6vw,20px)}
.g-2{grid-template-columns:repeat(2,1fr)}
.g-3{grid-template-columns:repeat(3,1fr)}
.g-4{grid-template-columns:repeat(4,1fr)}
.g-main{grid-template-columns:1.55fr .95fr;align-items:start}

/* A grid item will not shrink below the width of its own content unless it is
   told it may. Without this, one row of buttons that cannot wrap widens its
   column, widens the grid, and pushes the whole page off the side of the
   screen - which is exactly what a crew invite did. */
.shell>*,.grid>*{min-width:0}

/* ---------- tabs ---------- */
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin-bottom:20px}
.tabs a{
  padding:11px 16px;font-size:14.5px;font-weight:700;color:var(--slate-500);
  border-bottom:2px solid transparent;margin-bottom:-1px;transition:color .18s,border-color .18s;
}
.tabs a:hover{color:var(--slate-200)}
.tabs a.active{color:var(--white);border-bottom-color:var(--white)}

/* ---------- lists ---------- */
/* A row is an avatar, some text, and whatever buttons belong to it. On a narrow
   column the buttons drop onto their own line rather than squeezing the text
   into one word per line - which is what happens if the text is simply allowed
   to shrink to nothing. flex-basis on .grow is what forces the wrap. */
.row{display:flex;align-items:center;gap:14px;row-gap:10px;flex-wrap:wrap;
     padding:14px 0;border-bottom:1px solid var(--line)}
.row:last-child{border-bottom:0}
.row .grow{flex:1 1 190px;min-width:0}
.row .name{font-weight:700;font-size:15px}
.row .sub{font-size:13px;color:var(--slate-500);margin-top:2px}

/* ---------- tables (The Smith) ---------- */
.table{width:100%;border-collapse:collapse;font-size:14.5px}
.table th{
  text-align:left;font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--slate-500);font-weight:800;padding:0 14px 12px;
}
.table td{padding:13px 14px;border-top:1px solid var(--line);color:var(--slate-200)}
.table tr:hover td{background:rgba(148,163,184,.04)}
.table td.num{font-variant-numeric:tabular-nums;color:var(--white);font-weight:600}

/* ---------- forms ---------- */
.field{display:grid;gap:7px;margin-bottom:16px}
.field label{font-size:13px;font-weight:700;color:var(--slate-300)}
.field input,.field select,.field textarea{
  background:var(--bg-2);border:1px solid var(--line-2);border-radius:12px;
  padding:12px 14px;font-size:15px;color:var(--white);width:100%;
  transition:border-color .2s,background .2s;
}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--slate-500);background:var(--panel);
}
.field .hint{font-size:12.5px;color:var(--slate-500)}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
/* Sets / Reps / Warm-ups. Without this the third one wraps onto its own
   line and looks like it belongs to something else. */
.field-row.three{grid-template-columns:1fr 1fr 1fr}

/* ---------- empty states (cold start) ---------- */
.empty{
  text-align:center;padding:clamp(32px,5vw,56px) 24px;
  border:1px dashed var(--line-2);border-radius:var(--r-lg);background:rgba(148,163,184,.03);
}
.empty h3{margin-bottom:10px}
.empty p{max-width:46ch;margin:0 auto 20px;font-size:15px}

/* ---------- stats ---------- */
.stat-tile{padding:20px 22px;border-radius:var(--r);background:var(--panel);border:1px solid var(--line);container-type:inline-size}
.stat-tile .k{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--slate-500);font-weight:800}
.stat-tile .v{font-family:var(--display);font-size:clamp(22px,2.4vw,30px);font-weight:800;margin-top:8px;letter-spacing:-.03em;white-space:nowrap}
.stat-tile .d{font-size:13px;color:var(--slate-500);margin-top:4px}
/* 🚩 Measured, not guessed. Two stat tiles side by side in the narrow right-hand
   column are 142px wide on a desktop, leaving 96px inside the padding - and the
   week's volume, "22,830 kg", is 118px at the full display size. It hung over
   the edge of its own tile. The tiles are sized by their column and not by the
   viewport, so a media query is the wrong tool: this asks the tile how wide IT
   is. Everything wider keeps the big figure. */
@container (max-width:170px){
  .stat-tile{padding:16px 16px}
  .stat-tile .v{font-size:21px}
}

/* ---------- reveal on scroll (the "modern" movement) ---------- */
.reveal{opacity:0;transform:translateY(18px);transition:opacity .7s cubic-bezier(.2,.7,.3,1),transform .7s cubic-bezier(.2,.7,.3,1)}
.reveal.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none;transition:none}
  .btn:hover,.card:hover{transform:none}
}

/* ---------- footer ---------- */
.foot{border-top:1px solid var(--line);margin-top:clamp(48px,6vw,84px);padding:52px 0 40px}
.foot .cols{display:grid;grid-template-columns:1.5fr repeat(3,1fr);gap:36px}
.foot h4{font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--slate-500);margin-bottom:16px;font-family:var(--body);font-weight:800}
.foot ul{list-style:none;display:grid;gap:10px}
.foot a{color:var(--slate-300);font-size:14.5px}
.foot a:hover{color:var(--white)}
.foot .bot{margin-top:44px;padding-top:24px;border-top:1px solid var(--line);display:flex;flex-wrap:wrap;gap:14px;font-size:13px;color:var(--slate-700)}
.foot .bot .r{margin-left:auto}

/* ---------- responsive ---------- */
@media(max-width:1000px){
  .g-main,.g-4{grid-template-columns:repeat(2,1fr)}
  .shell{grid-template-columns:1fr}
  .side{position:static;display:none}
  .side.open{display:block}
}
/* Was 760px. Between 760 and 900 the five nav links, the logo and the header
   buttons together are wider than the screen, which pushed every page sideways.
   Measured, not guessed - at 820px the document was 828px wide. */
@media(max-width:1060px){
  .nav{display:none}
  .nav.open{
    display:flex;flex-direction:column;align-items:stretch;gap:2px;
    position:absolute;top:70px;left:0;right:0;padding:14px var(--gut) 20px;
    background:var(--bg);border-bottom:1px solid var(--line);box-shadow:0 24px 40px -20px rgba(0,0,0,.95);
  }
  .burger{display:block}
  .topbar .actions{margin-left:0}
  .g-2,.g-3,.g-4,.g-main,.field-row{grid-template-columns:1fr}
  .foot .cols{grid-template-columns:1fr 1fr}
}
/* On a phone the two header buttons don't both fit - Sign in moves into the burger
   menu so "Join the Brotherhood" is never clipped off the edge of the screen. */
@media(max-width:520px){
  .topbar .actions .signin-btn{display:none}
  /* Signed in, the same problem: the bell, the messages icon and a Dashboard
     button do not all fit next to the logo. Dashboard is the first item in the
     side menu anyway, so it is the one that goes. */
  .topbar .actions .dash-btn{display:none}
  .topbar .actions .btn-primary{white-space:nowrap;font-size:12.5px;padding:9px 14px}
  .topbar .inner{gap:10px}
  .nav.open .signin-mob{display:block;margin-top:10px;padding-top:12px;border-top:1px solid var(--line)}
}
/* Below this the wordmark and "Join the Brotherhood" still fight for the same
   30 pixels on a small Android. The mark keeps the brand; the words go.
   Measured at 360px, where the page was 390px wide before this. */
@media(max-width:430px){
  .brand .name{font-size:15px}
  .brand{gap:8px}
  .topbar .actions .btn-primary{font-size:12px;padding:9px 12px}
  .topbar .inner{gap:8px}
}
/* An old 320px handset. Nothing shrinks far enough, so the wordmark drops and
   the GB mark carries the brand on its own. */
@media(max-width:340px){
  .brand .name{display:none}
}
.signin-mob{display:none}

/* ---------------------------------------------------------------------------
   Flash messages. Every action that writes says so - a button that looks like
   it worked but didn't is worse than one that plainly failed.
   Kept monochrome like the rest; errors read louder through weight and a rule,
   not through colour, because the palette has no red in it.
--------------------------------------------------------------------------- */
.flashes{position:sticky;top:0;z-index:60;padding:12px 0 0}
.flash{
  display:flex;align-items:flex-start;gap:14px;
  background:var(--panel-2);border:1px solid var(--line-2);border-left:3px solid var(--slate-500);
  border-radius:var(--r);padding:13px 16px;margin-bottom:10px;
  font-size:14.5px;line-height:1.5;color:var(--slate-100);
  box-shadow:var(--shadow);
  animation:flash-in .28s cubic-bezier(.2,.7,.3,1) both;
}
.flash span{flex:1;min-width:0}
.flash-success{border-left-color:var(--white)}
.flash-error{border-left-color:var(--white);font-weight:600}
.flash-x{
  background:none;border:0;color:var(--slate-500);font-size:20px;line-height:1;
  cursor:pointer;padding:0 2px;transition:color .15s;
}
.flash-x:hover{color:var(--white)}
@keyframes flash-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.flash{animation:none}}

/* An inline form should not knock the layout about - it is only there to carry
   the CSRF token and the button that was already in the design. */
form.inline{display:contents}

/* Label that only a screen reader needs to hear. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ---------------------------------------------------------------------------
   Preview screens - the look inside for men who have not joined.

   The banner is deliberately plain and sits above the content rather than
   floating over it: a man must be able to tell at a glance that the lads and
   the workouts on the page are examples, and a notice that can be scrolled
   under or dismissed does not do that job.
--------------------------------------------------------------------------- */
.preview-note{
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;row-gap:12px;
  background:var(--panel-2);border:1px solid var(--line-2);border-left:3px solid var(--white);
  border-radius:var(--r);padding:16px 20px;margin-bottom:24px;
}
.preview-note .pn-tag{
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;font-weight:800;
  color:var(--white);background:var(--panel-hi);border:1px solid var(--line-2);
  padding:5px 11px;border-radius:999px;flex:none;
}
.preview-note p{flex:1 1 320px;min-width:0;font-size:14.5px;color:var(--slate-300);margin:0}
.preview-note .btn{flex:none}

.preview-foot{
  text-align:center;margin-top:28px;padding:clamp(30px,4vw,48px) 24px;
  border:1px dashed var(--line-2);border-radius:var(--r-lg);background:rgba(148,163,184,.03);
}
.preview-foot h3{margin-bottom:10px}
.preview-foot p{max-width:52ch;margin:0 auto 22px;font-size:15px}

/* Menu items with nothing honest to preview - a man's own messages, alerts and
   settings. Shown greyed rather than removed so the menu is the same shape
   before and after he joins. */
.side-off{
  display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:12px;
  font-size:14.5px;font-weight:600;color:var(--slate-700);cursor:default;
}
.side-off .ico{width:18px;height:18px;flex:none;opacity:.5}

/* Ticked list on the waiting room - what a man has already got, as opposed to
   what is still shut. The tick is a pseudo-element rather than an inline SVG
   per item because it repeats and carries no meaning a screen reader needs. */
.ticks{list-style:none;display:grid;gap:10px}
.ticks li{
  position:relative;padding-left:28px;font-size:15px;color:var(--slate-200);
  line-height:1.5;word-break:break-word;
}
.ticks li::before{
  content:"";position:absolute;left:0;top:.42em;width:13px;height:7px;
  border-left:2px solid var(--white);border-bottom:2px solid var(--white);
  transform:rotate(-45deg);border-radius:1px;
}

/* --- The Smith: what to go for next time, and whether it is moving ----------
   A log is a record; these two turn it into a plan. Same locked palette - the
   trend line is slate on black, never a green "good" or a red "bad". A man
   having a flat month does not need the app colouring it in for him. */
.nexts{display:grid;gap:10px}
.next{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;padding:14px 16px;
  border:1px solid var(--line);border-radius:var(--r);background:var(--panel-2)}
.next .lift{font-weight:700;color:var(--white);flex:1 1 150px;min-width:0}
.next .was{font-size:13.5px;color:var(--slate-500);white-space:nowrap}
.next .opts{display:flex;flex-wrap:wrap;gap:8px}
.goal{display:inline-flex;align-items:baseline;gap:7px;padding:7px 13px;border-radius:999px;
  background:var(--panel-hi);color:var(--white);font-size:14px;font-weight:700;white-space:nowrap}
.goal small{font-size:12px;font-weight:600;color:var(--slate-400)}
.trend{display:flex;align-items:center;gap:14px;padding:13px 0;border-bottom:1px solid var(--line)}
.trend:last-of-type{border-bottom:0}
.trend .grow{min-width:0}
.trend svg{flex:0 0 auto;display:block}
.trend polyline{fill:none;stroke:var(--slate-200);stroke-width:2;
  stroke-linejoin:round;stroke-linecap:round}

/* --- The Crew: a man is not a table row -------------------------------------
   Every block on this page used the same `.row` strip - the sessions, the men,
   and the explainer of how the fit is worked out - so the screen read as one
   long list of identical entries, each with a number boxed on the end. His
   words were "tick boxy", and he was right: three unrelated kinds of content
   were wearing the same component.
   A man you might train with now gets a card. The reason he came up is said in
   words rather than printed as a score, and the score is demoted to the small
   grey line it should always have been. */
.mates{display:grid;gap:12px}
.mate{
  display:grid;grid-template-columns:auto 1fr auto;gap:16px;align-items:center;
  padding:16px 18px;border:1px solid var(--line);border-radius:var(--r-lg);
  background:var(--panel-2);
  transition:border-color .2s,transform .2s cubic-bezier(.2,.7,.3,1),background .2s;
}
.mate:hover{border-color:var(--line-2);transform:translateY(-2px);background:var(--panel-hi)}
.mate .avatar{width:52px;height:52px;font-size:17px}
.mate .who{min-width:0}
.mate .who .n{font-family:var(--display);font-weight:800;font-size:18px;letter-spacing:-.018em;color:var(--white)}
.mate .who .where{font-size:13.5px;color:var(--slate-400);margin-top:4px}
.tags{display:flex;flex-wrap:wrap;gap:7px;margin-top:10px}
/* The fit reads as the first reason rather than a number in a box on the end. */
.tag-fit{background:var(--white);border-color:var(--white);color:#0A0E13}
.tag{
  font-size:12px;font-weight:700;padding:5px 12px;border-radius:999px;
  background:var(--panel-hi);border:1px solid var(--line);color:var(--slate-200);
  white-space:nowrap;
}
.mate .act{display:flex;flex-direction:column;align-items:flex-end;gap:10px;flex:none}
.mate .act .strength{font-size:13px;font-weight:700;color:var(--white);white-space:nowrap}
.mate .act .out-of{font-size:11.5px;color:var(--slate-500);margin-top:-6px}

@media (max-width:640px){
  /* Stack it. The action column pinned to the right of a 340px card leaves the
     name two words wide. */
  .mate{grid-template-columns:auto 1fr;gap:14px;padding:16px}
  .mate .act{grid-column:1 / -1;flex-direction:row;align-items:center;justify-content:space-between;
             width:100%;margin-top:4px}
  .mate .act .out-of{margin-top:0}
}

/* --- The Forge, to his mockup ------------------------------------------------
   A feed, not a list of panels: a filter row across the top, a composer that
   asks a question rather than showing a form, and posts as cards with the reply
   tucked under them. "I've got you" instead of a like - his words, and the right
   ones for what the button actually means here. */
.forge-head{margin-bottom:22px}
.forge-head h1{font-size:clamp(34px,4.4vw,54px);line-height:1.03}
.forge-head .sub{color:var(--accent);font-size:clamp(15px,1.5vw,18px);font-weight:700;margin-top:8px}

.filters{
  display:flex;gap:4px;padding:5px;margin-bottom:16px;
  background:var(--panel);border:1px solid var(--line);border-radius:999px;
  overflow-x:auto;scrollbar-width:none;
}
.filters::-webkit-scrollbar{display:none}
.filters a{
  flex:1 1 auto;text-align:center;white-space:nowrap;padding:10px 16px;border-radius:999px;
  font-size:14px;font-weight:700;color:var(--slate-400);transition:color .18s,background .18s;
}
.filters a:hover{color:var(--white);background:rgba(148,163,184,.07)}
.filters a.active{color:var(--white);background:var(--panel-hi);box-shadow:var(--shadow)}

/* The composer. Opens as a question; the fields only appear once he answers it. */
.composer{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--panel);padding:18px 20px;margin-bottom:18px}
.composer .top{display:flex;align-items:center;gap:14px}
.composer .ask{
  flex:1;background:none;border:0;text-align:left;cursor:pointer;padding:12px 0;
  font-family:var(--body);font-size:16.5px;color:var(--slate-400);
}
.composer .ask:hover{color:var(--slate-200)}
.composer .chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px;align-items:center}
.composer .chips .spacer{margin-left:auto}
.chip-btn{
  display:inline-flex;align-items:center;gap:7px;padding:8px 14px;border-radius:999px;
  background:var(--panel-2);border:1px solid var(--line);color:var(--slate-200);
  font-size:13.5px;font-weight:700;cursor:pointer;transition:border-color .18s,background .18s,color .18s;
}
.chip-btn:hover{border-color:var(--line-2);color:var(--white);background:var(--panel-hi)}
.chip-btn.on{background:var(--white);border-color:var(--white);color:#0A0E13}

.post{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--panel);padding:18px 20px}
.post + .post{margin-top:14px}
.post .who{display:flex;align-items:center;gap:12px}
.post .who .n{font-weight:700;font-size:15px;color:var(--white)}
.post .who .badge-crew{
  display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--slate-500);
}
.post .who .when{margin-left:auto;font-size:13px;color:var(--slate-500);white-space:nowrap}
.post .body{margin-top:12px;font-size:15.5px;line-height:1.6;color:var(--slate-200)}
.post .acts{display:flex;align-items:center;gap:8px;margin-top:14px}
.post .acts .report{margin-left:auto;font-size:12.5px;color:var(--slate-700)}
.post .acts .report:hover{color:var(--slate-400)}
.gotyou{
  display:inline-flex;align-items:center;gap:8px;padding:8px 14px;border-radius:999px;
  background:none;border:1px solid transparent;color:var(--slate-400);
  font-size:13.5px;font-weight:700;cursor:pointer;transition:color .18s,background .18s;
}
.gotyou:hover{color:var(--white);background:rgba(148,163,184,.07)}
.gotyou.on{color:var(--white);background:var(--panel-hi);border-color:var(--line-2)}

/* A reply sits inside the post it answers, indented and a shade lighter. */
.reply{
  display:flex;gap:12px;margin-top:14px;padding:14px 16px;
  background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r);
}
.reply .n{font-weight:700;font-size:14px;color:var(--white)}
.reply .when{margin-left:auto;font-size:12.5px;color:var(--slate-500);white-space:nowrap}
.reply .t{font-size:14.5px;color:var(--slate-300);margin-top:5px;line-height:1.55}

/* Right column: who's about, and the three rules. */
.whos-about .row:last-child{border-bottom:0}
.rule-item{display:flex;gap:14px;padding:14px 0;border-bottom:1px solid var(--line)}
.rule-item:last-child{border-bottom:0}
.rule-item .ico{color:var(--slate-400);flex:none;margin-top:1px}
.rule-item .t{font-family:var(--display);font-weight:800;font-size:15.5px;letter-spacing:-.01em}
.rule-item .d{font-size:13.5px;color:var(--slate-500);margin-top:4px}

@media (max-width:640px){
  .filters a{flex:0 0 auto;padding:9px 14px;font-size:13.5px}
  .post .who{flex-wrap:wrap}
  .post .who .when{margin-left:0;width:100%}
  /* The chips wrap on a phone, which left the post button stranded on its own
     line hard against the left edge, reading like another chip. Give it the
     full width and it reads as the action it is. */
  .composer .chips .spacer{display:none}
  .composer .chips .btn{width:100%;margin-top:4px}
}


/* --- Layering, and reading it on a phone -------------------------------------
   His two notes, and they turn out to be the same note. The page was one flat
   black from top to bottom - six of the ten sections had no background at all -
   so nothing told you where one idea ended and the next began. And the small
   print was set in a grey that measured under the readability floor on every
   surface, at 13.5px, on a 390px screen.

   Sections now alternate between the page black and a slightly raised band,
   with a hairline between them. Nothing loud - it is still a black site - but
   there is a floor and a wall now instead of one dark room. */
.blk{position:relative}
.blk + .blk{border-top:1px solid var(--line)}

.tint{background:var(--bg-2)}
.tint::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(90% 60% at 50% 0%,rgba(140,165,201,.055),transparent 70%);
}
.tint > *{position:relative;z-index:1}

/* On a phone, everything small gets a size up and the leading opens out. A line
   of 13.5px grey at arm's length on a bus is not reading, it is squinting. */
@media(max-width:640px){
  body{font-size:16.5px;line-height:1.68}
  p{line-height:1.68}
  .meta,.muted,.fine,.sub{font-size:14.5px;line-height:1.6}
  .head p,.themission p,.area p,.post .body{font-size:16.5px;line-height:1.68}
  .eyebrow{font-size:11px;letter-spacing:.14em}
  /* Long paragraphs need more air between them than between their own lines. */
  .head p + p,.themission p + p{margin-top:18px}
}


/* --- Keeping a post ---------------------------------------------------------
   A ribbon at the end of the action row. Private: keeping something tells the
   author nothing, which is the point - a man will not keep a post about a bad
   week if it fires off a notification to whoever wrote it. */
.keep{
  display:inline-flex;align-items:center;gap:7px;padding:8px 13px;border-radius:999px;
  background:none;border:1px solid transparent;color:var(--slate-500);
  font-family:inherit;font-size:13.5px;font-weight:700;cursor:pointer;
  transition:color .18s,background .18s,border-color .18s;
}
.keep:hover{color:var(--white);background:rgba(148,163,184,.07)}
.keep.on{color:var(--white);background:var(--panel-hi);border-color:var(--line-2)}
.post .acts .report{margin-left:14px}
@media(max-width:640px){
  /* The row wraps on a phone; the ribbon should not be stranded mid-line. */
  .post .acts form.inline{margin-left:0 !important}
  .post .acts{flex-wrap:wrap;row-gap:4px}
}

/* ---------------------------------------------------------------------------
   THE SMITH, SET BY SET
   His brief after showing me Alpha Progression: "it's mostly the depth... Can
   we try to flesh out the Smith a bit more, it feels very 1 dimensional when
   this is primarily where a lot of a GBUK users time will be spent", plus the
   90-second cooldown and a picture of how the lift is done.

   The shape is Alpha's - a row per set, the live one picked out, tick to
   finish - in our palette. Alpha uses green for done; we have no green, so
   done is white on black and finished sets grey off. That reads as MORE
   finished, not less, which suits a site that is mostly black anyway.
--------------------------------------------------------------------------- */
.lifts{display:grid;gap:16px;padding-top:18px}

/* 🚩 `.liftcard`, not `.lift`. `.lift` was already taken - it is the lift NAME
   inside the "Next time" panel (`.next .lift`) and on the preview page - so
   this card's border, padding and panel background were landing on those
   little text spans too. Caught by a Playwright count: eight `.lift` on a
   page with two lifts on it. */
.liftcard{
  border:1px solid var(--line);border-radius:var(--r-lg);background:var(--panel-2);
  padding:clamp(14px,2vw,20px);transition:border-color .2s,opacity .2s;
}
.liftcard.is-done{opacity:.72}
.liftcard.is-done:hover{opacity:1}
/* A day that has not happened yet. Quieter and flatter than today's card, so
   a glance down the page tells him which one he is actually training. */
.liftcard.planned{background:var(--panel);border-style:dashed}
.planday{margin-bottom:22px}
.planday:last-of-type{margin-bottom:6px}
.planday h4{font-family:var(--display);font-weight:800;font-size:14px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--slate-400);margin:0 0 10px}
.planday .liftcard{margin-bottom:12px}

/* The form picture and the one-line cue. */
.lift-how{
  display:flex;gap:13px;align-items:center;padding:11px;border-radius:14px;
  background:var(--panel);border:1px solid var(--line);margin-bottom:15px;
}
/* Height is fixed, width is whatever the drawing is. Squaring them was the
   first attempt and it shrank the wide ones (press-up, seated row) into
   smudges - see to_tile() in tools/build_lift_drawings.py. */
.lift-how img{height:100px;width:auto;max-width:170px;border-radius:11px;flex:none;
  background:#000;object-fit:contain}
.lift-how .h{font-family:var(--display);font-weight:800;font-size:13.5px;color:var(--white)}
.lift-how .d{font-size:12.5px;color:var(--slate-400);margin-top:4px;line-height:1.45}
.lift-how .c{font-size:10.5px;color:var(--slate-600);margin-top:6px}
.lift-how .c a{color:var(--slate-500);text-decoration:underline}

.lift-head{display:flex;align-items:flex-start;gap:12px}
.lift-head h3{font-family:var(--display);font-weight:800;font-size:clamp(19px,2vw,23px);
  letter-spacing:-.022em;color:var(--white);margin:0}
.lift-head .meta{font-size:13px;color:var(--slate-400);margin-top:4px}
.lift-tools{margin-left:auto;display:flex;align-items:center;gap:8px;flex:none}
.lift-head .tickpill{display:flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:999px;background:var(--white);color:#0A0E13;flex:none}
/* Bin the whole lift. Quiet by default - it is destructive, and it should not
   compete with the tick for his thumb - but a proper 34px target, because he
   is using this one-handed. */
.droplift{display:flex;align-items:center;justify-content:center;width:34px;height:34px;
  border-radius:999px;background:none;border:0;padding:0;cursor:pointer;color:#3F4A5C;
  transition:color .18s,background .18s}
.droplift:hover,.droplift:focus-visible{color:var(--slate-200);background:var(--panel-hi)}

.warm-row{margin-top:12px}
.warm{display:inline-block;padding:5px 12px;border-radius:999px;background:var(--panel-hi);
  border:1px solid var(--line);font-size:12px;font-weight:700;color:var(--slate-200)}

/* The set table. A grid, not a <table>, because the live row is a form and a
   form cannot be a table row without display juggling that breaks on Safari. */
.stable{margin-top:14px}
.shead,.srow{display:grid;grid-template-columns:44px 1fr 1fr 74px 46px;gap:8px;align-items:center}
.shead{padding-bottom:9px;border-bottom:1px solid var(--line)}
.shead span{font-size:10px;letter-spacing:.11em;text-transform:uppercase;color:var(--slate-500);
  font-weight:800;text-align:center}
.srow{padding:6px 0;margin:0}
.srow .sn,.srow .sv{text-align:center;font-size:15.5px;font-weight:700}
.srow.done .sn,.srow.done .sv{color:var(--slate-500)}
.srow.todo .sn,.srow.todo .sv{color:#3F4A5C}
/* A planned day's numbers are the plan, not a placeholder - readable, but
   still clearly not something he has done. */
.srow.todo.plan .sn,.srow.todo.plan .sv{color:var(--slate-500)}
.srow.live .est{color:var(--accent)}
.srow.busy{opacity:.5;pointer-events:none}

/* The live row's white pills. These are real number inputs - he taps one and
   gets the numeric keypad, which is the whole reason not to fake it with a
   contenteditable div. */
.srow .p{
  display:block;width:100%;box-sizing:border-box;background:var(--white);color:#0A0E13;
  border:0;border-radius:999px;padding:10px 4px;font-family:inherit;font-weight:800;
  font-size:16px;text-align:center;-moz-appearance:textfield;
}
.srow .p::-webkit-outer-spin-button,.srow .p::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.srow b.p{padding:10px 0}
.srow .p:focus{outline:2px solid var(--accent);outline-offset:2px}

.tick{display:flex;align-items:center;justify-content:center;background:none;border:0;
  padding:0;cursor:pointer;color:inherit;margin:0 auto}
.tick.dt{color:var(--slate-500);width:34px;height:34px;border-radius:999px}
.tick.dt:hover{color:var(--white);background:var(--panel-hi)}
.tick.drop{color:#3F4A5C;width:34px;height:34px;border-radius:999px}
.tick.drop:hover{color:var(--slate-300);background:var(--panel-hi)}
.tick.go{width:42px;height:42px;border-radius:999px;background:var(--white);color:#0A0E13}
.tick.go:hover{transform:scale(1.05)}

.lift-foot{display:flex;align-items:center;gap:12px;margin-top:12px;flex-wrap:wrap}
.lift-foot .restform{display:flex;align-items:center;gap:8px;margin-left:auto}
.restlab{font-size:11px;letter-spacing:.11em;text-transform:uppercase;color:var(--slate-500);font-weight:800}
.lift-foot select{background:var(--panel-hi);color:var(--slate-200);border:1px solid var(--line);
  border-radius:999px;padding:7px 12px;font-family:inherit;font-size:13px;font-weight:700}

/* What he did last time, right under the sets he is doing now. */
.lastwk{margin-top:14px;padding:12px 14px;border-radius:13px;background:var(--panel);
  border:1px solid var(--line)}
.lwt{font-size:10px;letter-spacing:.11em;text-transform:uppercase;color:var(--slate-500);
  font-weight:800;margin-bottom:7px}
.lwr{display:grid;grid-template-columns:44px 1fr 1fr 74px;gap:8px;font-size:13px;
  color:var(--slate-400);padding:2px 0;text-align:center}

/* The cooldown. Idle it is quiet; running it is the brightest thing on the
   screen, because that is the one number he is looking for across the gym. */
.rest{
  width:100%;margin-top:15px;padding:14px;border-radius:999px;background:var(--panel-hi);
  border:1px solid var(--line-2);color:var(--slate-200);font-family:inherit;font-size:15px;
  font-weight:800;display:flex;align-items:center;justify-content:center;gap:10px;cursor:pointer;
  transition:background .18s,color .18s,border-color .18s;
}
/* This button ships `hidden` and the script unhides it. What makes that
   stick is the global [hidden] rule at the top of this file - see the note
   there, because `display:flex` on the line above would otherwise win. */
.rest:hover{border-color:var(--line-2);color:var(--white)}
.rest.running{background:var(--white);color:#0A0E13;border-color:var(--white)}
.rest.over{background:var(--accent);color:#08101B;border-color:var(--accent)}

/* Writing up an old session - folded away, because it is the rarer of the two. */
details.after{margin-top:18px;border-top:1px solid var(--line);padding-top:14px}
details.after summary{cursor:pointer;font-size:13.5px;color:var(--slate-400);font-weight:700}
details.after summary:hover{color:var(--slate-200)}
details.after>*:not(summary){margin-top:14px}

.table tr.planned td{color:var(--slate-600)}

@media(max-width:560px){
  /* Est. 1RM is the first thing to go. He can read it off the log afterwards;
     between sets he needs the weight, the reps and the tick. */
  .shead,.srow{grid-template-columns:38px 1fr 1fr 42px}
  /* By CLASS, not :nth-child - the live row is a form and {% csrf_token %}
     puts a hidden input first, so the positions differ from the other two
     states even though the grid lays them out the same. */
  .shead .est,.srow .est,.lwr .est{display:none}
  .lwr{grid-template-columns:38px 1fr 1fr}
  .lift-how img{height:76px;max-width:128px}
  .lift-foot .restform{margin-left:0;width:100%}
}
