/* ==========================================================================
   FILE          assets/cut-society.css
   UPLOAD TO     public_html/assets/cut-society.css
   LOADED        after aes.css, aes-atom.css and aes-type.css,
                 and BEFORE aes-nav.css (which stays the header authority).

   WHAT THIS FILE IS
   -----------------
   The salon layer. Every rule here sits on top of the AES design system
   carried over from jjmccaffrey.com. aes.css, aes-atom.css, aes-nav.css,
   aes-type.css, aes-atom.js and aes-sound.js are UNCHANGED, so a fix made
   on jjmccaffrey.com drops straight in here without a merge.

   This file does three things and nothing else:

     1. Re-points the AES colour variables at the salon palette.
     2. Adds the components the salon needs and the AES site has no
        equivalent of — price rows, the roster, the gallery grid, the
        booking flow.
     3. Keeps the blade angle from the Cut Society brief alive inside the
        AES chassis.

   TO REVERT THE PALETTE to the AES navy-and-red exactly as it runs on
   jjmccaffrey.com: delete block 1 below. Nothing else depends on it.
   ========================================================================== */


/* ==========================================================================
   1. PALETTE
   The AES variables keep their names, so every AES rule still resolves.
   Only the values move: boardroom navy becomes salon black, and the AES
   signal red becomes the chrome accent the Cut Society brief asked for.
   ========================================================================== */
:root{
  --ink:#050505;             /* true black base                             */
  --wall:#0A0B0D;           /* page background                             */
  --panel:#141619;          /* raised surface, cool black                  */
  --panel-2:#1C1F23;        /* hover surface                               */
  --line:rgba(184,188,194,.16);
  --line-soft:rgba(184,188,194,.09);
  --steel:#D6D2CC;          /* body text                                   */
  --mute:#9AA0A7;           /* secondary text                              */
  --white:#EDE9E3;          /* bone                                        */

  /* The AES red slot now carries chrome. Every ::before rule, every
     .btn.primary and every card spine follows it automatically. */
  --red:#B8BCC2;
  --red-soft:rgba(184,188,194,.16);
  --blue:#5E646C;
  --blue-soft:rgba(94,100,108,.16);
  --halo:#F4F6F8;           /* specular highlight, was warm backlight      */
  --halo-soft:rgba(244,246,248,.10);

  /* the atom's own two variables, so the panel chrome matches */
  --atom-glow:#9AA0A8;
  --atom-ring:#D8DCE2;

  /* the one idea from the Cut Society brief that survives the transplant */
  --cut-angle:4deg;
  --chamfer:14px;

  --maxw:1180px;
  --r:0px;                  /* nothing on this site is rounded             */
}

/* The AES background is a navy wash with a red bloom. Same construction,
   salon values: a cold overhead light and a warm floor bounce. */
body{
  background:
    radial-gradient(1100px 640px at 50% -220px, rgba(184,188,194,.08), transparent 62%),
    radial-gradient(900px 560px at 88% 112%, rgba(120,126,134,.05), transparent 55%),
    linear-gradient(180deg,#08090B 0%, var(--wall) 42%, #060708 100%);
  background-attachment:fixed;
}

/* Corners. The AES system rounds; this site cuts. One rule, everything
   follows — the only survivor is the atom core, which is a circle by
   nature rather than a rounded rectangle. */
.btn,.card,.panel,.smr-panel,.skillcol,.cfield input,.cfield textarea,
.dl-card,.svc-block,.ai-model,.qual-strip span,.sector-strip span,
.hero-tags span,.nav-burger,.vclose,.psel,.pbtn{
  border-radius:0;
}


/* ==========================================================================
   2. TYPE
   Microgramma stays the display face — it is already an industrial,
   squared-off letterform, which is exactly what the brief asked for and
   saves a second font download. Chakra Petch is not loaded.
   ========================================================================== */
.eyebrow{
  font-family:"Orbitron",sans-serif;font-weight:800;font-size:13.5px;
  letter-spacing:.05em;text-transform:uppercase;color:#7C8794;
  text-shadow:0 -1px 1px rgba(0,0,0,.85),0 -2px 2px rgba(0,0,0,.5),
              0 1px 0 rgba(210,222,236,.28),0 2px 2px rgba(210,222,236,.12);
  display:inline-flex;align-items:center;gap:10px;margin:0 0 14px;
}
.eyebrow::before{content:"";width:22px;height:2px;background:var(--red);flex:none}

.lede{color:var(--mute);font-size:17.5px;max-width:62ch;margin:0}

/* The statement line. The cut runs through it at the brief's blade angle
   rather than underlining it. */
.statement{
  font-family:"Microgramma","Orbitron",sans-serif;text-transform:uppercase;
  font-size:clamp(24px,4.2vw,52px);line-height:1.14;letter-spacing:.005em;
  color:var(--white);position:relative;margin:0;
}
.statement em{font-style:normal;color:var(--mute)}
.statement::after{
  content:"";position:absolute;left:0;right:0;top:var(--cut-at,50%);
  height:2px;background:var(--red);opacity:.55;
  transform:rotate(calc(var(--cut-angle) * -1));transform-origin:left center;
  pointer-events:none;
}
@media(prefers-reduced-motion:reduce){.statement::after{transform:none}}


/* ==========================================================================
   3. THE WORDMARK
   The supplied artwork, traced to vector and rendered in chrome. Three
   gradient layers do the metal; see cs_wordmark() in the build script.

   The mark is 2.76:1, so it is much taller relative to its width than a
   single-line wordmark. Widths below are set against that, not guessed.
   ========================================================================== */
.cs-mark{display:block;width:100%;height:auto}

/* The drifting specular bar. The only moving part of the logo, and the
   first thing to go when motion is not wanted. */
@media(prefers-reduced-motion:reduce){
  .cs-mark-spec{display:none}
  .cs-mark-spec animateTransform{display:none}
}

/* --- header ---------------------------------------------------------- */
header.nav .brand .cs-mark{width:116px}
@media(max-width:520px){header.nav .brand .cs-mark{width:92px}}

/* aes-nav.css sizes .brand img, which no longer exists — the mark is inline
   SVG now. This keeps the brand block from collapsing to zero height. */
header.nav .brand{min-width:0;flex:0 0 auto}

/* --- hero ------------------------------------------------------------- */
.hero-mark{width:min(560px,74vw);margin:0 auto 30px;
  filter:drop-shadow(0 14px 38px rgba(0,0,0,.7))}

/* --- footer and closing watermarks ------------------------------------ */
.foot-mark{width:min(300px,48vw);margin:0 0 26px;color:var(--panel-2)}


/* ==========================================================================
   4. HERO
   The AES hero is built around a backlit photograph. The salon has no
   photograph yet, so the wordmark carries the space and the rule below
   hides the image slot until a real file is dropped in.
   ========================================================================== */
.hero{background:var(--ink)}
.hero-in{padding:64px 28px 78px}
.hero .sub{max-width:52ch}

.hero-media{position:absolute;inset:0;overflow:hidden;z-index:0}
.hero-media img{width:100%;height:100%;object-fit:cover;opacity:.28;
  filter:grayscale(1) contrast(1.08)}
.hero-media::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(5,5,5,.55) 0%,rgba(5,5,5,.82) 100%)}

.hero-meta{
  font-family:"Share Tech Mono",ui-monospace,monospace;font-size:11.5px;
  letter-spacing:.16em;line-height:2;text-transform:uppercase;
  color:var(--mute);text-align:center;margin:0 0 8px;
}
.hero-meta b{color:var(--white);font-weight:400}


/* ==========================================================================
   5. THE TICKER
   The franchise towns, running. Pauses on hover so it can be read, and
   stops dead under prefers-reduced-motion.
   ========================================================================== */
.ticker{overflow:hidden;border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);background:rgba(5,5,5,.6);padding:14px 0}
.ticker-track{display:flex;width:max-content;animation:ticker 38s linear infinite}
.ticker-track:hover{animation-play-state:paused}
.ticker-track > span{display:flex;flex:none}
.ticker-track span span{
  font-family:"Orbitron",sans-serif;font-weight:800;font-size:13.5px;
  letter-spacing:.18em;text-transform:uppercase;color:#6E7883;
  padding:0 30px;white-space:nowrap;position:relative;
}
.ticker-track span span::after{content:"";position:absolute;right:0;top:50%;
  width:6px;height:6px;margin-top:-3px;background:var(--red);opacity:.5;
  transform:rotate(45deg)}
@keyframes ticker{to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){.ticker-track{animation:none}}


/* ==========================================================================
   6. PRICE ROWS
   A four-cell grid rather than a table, so it reflows to two lines on a
   phone without a horizontal scrollbar. The AES card spine is reused.
   ========================================================================== */
.price-group{margin-bottom:clamp(2.5rem,6vw,4rem)}
.price-group-title{
  font-family:"Microgramma","Orbitron",sans-serif;text-transform:uppercase;
  font-size:clamp(20px,2.6vw,26px);color:var(--white);
  padding-bottom:12px;border-bottom:1px solid var(--line);margin:0 0 10px;
}

a.price-row{
  position:relative;display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"name figure" "note dur";
  gap:4px 22px;align-items:baseline;
  padding:20px 22px;background:var(--panel);
  border:1px solid var(--line);border-top:0;overflow:hidden;
  transition:transform .18s,border-color .2s,background .2s;
}
.price-group a.price-row:first-of-type{border-top:1px solid var(--line)}
a.price-row::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--red);transform:scaleY(0);transform-origin:top;
  transition:transform .22s}
a.price-row:hover{background:var(--panel-2);border-color:rgba(184,188,194,.3)}
a.price-row:hover::before{transform:scaleY(1)}

.price-name{grid-area:name;font-family:"Orbitron",sans-serif;font-weight:700;
  font-size:17px;color:var(--white)}
.price-figure{grid-area:figure;font-family:"Orbitron",sans-serif;font-weight:800;
  font-size:19px;color:var(--white);white-space:nowrap}
.price-note{grid-area:note;font-size:14.5px;color:var(--mute);max-width:56ch}
.price-dur{grid-area:dur;font-family:"Share Tech Mono",ui-monospace,monospace;
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:#6E7883;
  white-space:nowrap;text-align:right}
@media(max-width:560px){
  a.price-row{grid-template-columns:1fr;
    grid-template-areas:"name" "figure" "note" "dur"}
  .price-figure,.price-dur{text-align:left}
}


/* ==========================================================================
   7. THE ROSTER
   ========================================================================== */
.roster{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}
@media(max-width:1000px){.roster{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.roster{grid-template-columns:1fr}}

.roster-card{position:relative;background:var(--panel);border:1px solid var(--line);
  overflow:hidden;transition:transform .18s,border-color .2s,background .2s}
.roster-card::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--red);transform:scaleY(0);transform-origin:top;
  transition:transform .22s;z-index:2}
.roster-card:hover{transform:translateY(-4px);border-color:rgba(184,188,194,.28);
  background:var(--panel-2)}
.roster-card:hover::before{transform:scaleY(1)}

.roster-photo{position:relative;aspect-ratio:3/4;background:
  linear-gradient(160deg,#16181C 0%,#0C0D10 100%);overflow:hidden}
.roster-photo img{width:100%;height:100%;object-fit:cover;
  filter:grayscale(1) contrast(1.06);transition:filter .3s}
.roster-card:hover .roster-photo img{filter:grayscale(.35) contrast(1.06)}
.roster-index{position:absolute;left:14px;top:12px;z-index:2;
  font-family:"Share Tech Mono",ui-monospace,monospace;font-size:11px;
  letter-spacing:.2em;color:var(--mute)}

.roster-body{padding:20px 22px 22px}
.roster-name{font-family:"Orbitron",sans-serif;font-weight:800;font-size:18px;
  color:var(--white);margin:0 0 4px;
  text-shadow:0 0 22px rgba(184,188,194,.18)}
.roster-spec{font-family:"Share Tech Mono",ui-monospace,monospace;font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--red);margin:0 0 10px}
.roster-bio{font-size:14.5px;color:var(--mute);margin:0}


/* ==========================================================================
   8. GALLERY
   ========================================================================== */
.gallery-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
@media(max-width:900px){.gallery-grid{grid-template-columns:repeat(2,1fr)}}

.gallery-item{position:relative;display:block;padding:0;overflow:hidden;
  aspect-ratio:1/1;cursor:pointer;background:
  linear-gradient(160deg,#16181C 0%,#0C0D10 100%);
  border:1px solid var(--line);transition:border-color .2s,transform .18s}
.gallery-item:hover{border-color:rgba(184,188,194,.34);transform:translateY(-3px)}
.gallery-item img{width:100%;height:100%;object-fit:cover;
  filter:grayscale(1) contrast(1.06);transition:filter .3s,transform .4s}
.gallery-item:hover img{filter:grayscale(0) contrast(1.06);transform:scale(1.04)}
.gallery-caption{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:26px 14px 12px;text-align:left;
  font-family:"Share Tech Mono",ui-monospace,monospace;font-size:10.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--white);
  background:linear-gradient(180deg,transparent,rgba(5,5,5,.88));
  opacity:0;transition:opacity .24s}
.gallery-item:hover .gallery-caption,
.gallery-item:focus-visible .gallery-caption{opacity:1}

.lightbox{position:fixed;inset:0;z-index:500;display:none;
  align-items:center;justify-content:center;padding:28px;
  background:rgba(5,5,5,.94);backdrop-filter:blur(6px)}
.lightbox.open{display:flex}
.lightbox figure{margin:0;max-width:min(1000px,94vw)}
.lightbox img{display:block;width:100%;height:auto;border:1px solid var(--line)}
.lightbox figcaption{margin-top:14px;
  font-family:"Share Tech Mono",ui-monospace,monospace;font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--mute)}
.lightbox-close,.lightbox-nav{
  position:absolute;background:none;border:1px solid var(--line);
  color:var(--steel);cursor:pointer;padding:10px 16px;
  font-family:"Share Tech Mono",ui-monospace,monospace;font-size:12px;
  letter-spacing:.16em;transition:color .2s,border-color .2s}
.lightbox-close:hover,.lightbox-nav:hover{color:var(--white);
  border-color:rgba(184,188,194,.4)}
.lightbox-close{top:22px;right:22px}
.lightbox-nav.prev{left:22px;top:50%;transform:translateY(-50%)}
.lightbox-nav.next{right:22px;top:50%;transform:translateY(-50%)}


/* ==========================================================================
   9. THE BOOKING FLOW
   Built in JavaScript after load, so site.js re-runs AESAtom.attach()
   after every render. Without that these would be the only controls on
   the site with no orbital and no sound — which is exactly where the
   feedback matters most.
   ========================================================================== */
.booking-shell{display:grid;grid-template-columns:1.4fr .6fr;gap:38px;
  align-items:start}
@media(max-width:900px){.booking-shell{grid-template-columns:1fr}}

.steps{list-style:none;display:flex;flex-wrap:wrap;gap:0;margin:0 0 30px;padding:0;
  border:1px solid var(--line)}
.step{flex:1 1 auto;padding:13px 16px;border-left:1px solid var(--line-soft);
  font-family:"Orbitron",sans-serif;font-weight:700;font-size:12.5px;
  letter-spacing:.06em;text-transform:uppercase;color:#5E646C;
  white-space:nowrap}
.step:first-child{border-left:0}
.step[data-state="current"]{color:var(--white);background:var(--panel-2);
  box-shadow:inset 3px 0 0 var(--red)}
.step[data-state="done"]{color:var(--mute)}
.step[data-state="done"]::before{content:"— ";color:var(--red)}

.choice{position:relative;display:block;width:100%;text-align:left;
  padding:16px 20px;margin-bottom:10px;overflow:hidden;cursor:pointer;
  background:var(--panel);border:1px solid var(--line);color:var(--steel);
  font-family:"Rajdhani",system-ui,sans-serif;font-size:16px;
  transition:background .2s,border-color .2s,transform .18s}
.choice::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--red);transform:scaleY(0);transform-origin:top;
  transition:transform .22s}
.choice:hover{background:var(--panel-2);border-color:rgba(184,188,194,.3)}
.choice:hover::before,.choice[aria-pressed="true"]::before{transform:scaleY(1)}
.choice[aria-pressed="true"]{background:var(--panel-2);
  border-color:rgba(184,188,194,.4)}
.choice-name{display:block;font-family:"Orbitron",sans-serif;font-weight:700;
  font-size:16px;color:var(--white);margin-bottom:3px}
.choice-meta{display:block;font-family:"Share Tech Mono",ui-monospace,monospace;
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--mute)}

.date-strip{display:flex;gap:8px;overflow-x:auto;padding-bottom:10px;
  margin-bottom:20px;scrollbar-width:thin}
.date-pill{position:relative;flex:none;padding:11px 15px;cursor:pointer;
  background:var(--panel);border:1px solid var(--line);color:var(--steel);
  font-family:"Share Tech Mono",ui-monospace,monospace;font-size:11.5px;
  letter-spacing:.1em;text-transform:uppercase;white-space:nowrap;
  overflow:hidden;transition:background .2s,border-color .2s}
.date-pill:hover{background:var(--panel-2)}
.date-pill[aria-pressed="true"]{background:var(--panel-2);color:var(--white);
  border-color:var(--red);box-shadow:inset 0 -2px 0 var(--red)}

.slot-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));
  gap:9px}
.slot{position:relative;padding:13px 8px;cursor:pointer;overflow:hidden;
  background:var(--panel);border:1px solid var(--line);color:var(--steel);
  font-family:"Share Tech Mono",ui-monospace,monospace;font-size:13px;
  letter-spacing:.06em;transition:background .2s,border-color .2s,color .2s}
.slot:hover{background:var(--panel-2);color:var(--white);
  border-color:rgba(184,188,194,.35)}
.slot[aria-pressed="true"]{background:var(--red);color:var(--ink);
  border-color:var(--red)}

.booking-summary{position:sticky;top:96px;background:var(--panel);
  border:1px solid var(--line);padding:24px}
.booking-summary h3{font-family:"Orbitron",sans-serif;font-weight:800;
  font-size:12.5px;letter-spacing:.06em;text-transform:uppercase;
  color:#7C8794;margin:0 0 16px}
.booking-summary .row{display:flex;justify-content:space-between;gap:14px;
  padding:10px 0;border-top:1px solid var(--line-soft);font-size:15px}
.booking-summary .row:first-of-type{border-top:0}
.booking-summary .row b{color:var(--white);font-weight:600;text-align:right}


/* ==========================================================================
   10. FORMS AND NOTICES
   ========================================================================== */
.field{display:block;margin-bottom:18px}
.field > span{display:block;font-family:"Share Tech Mono",ui-monospace,monospace;
  font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--mute);
  margin-bottom:8px}
.field input,.field textarea,.field select{
  width:100%;background:rgba(5,5,5,.6);border:1px solid var(--line);
  border-radius:0;color:var(--white);font-family:"Rajdhani",sans-serif;
  font-size:16px;padding:13px 15px;outline:none;transition:border-color .2s}
.field input:focus,.field textarea:focus,.field select:focus{
  border-color:var(--red)}

.notice{position:relative;padding:16px 20px 16px 24px;margin:0 0 20px;
  background:var(--panel);border:1px solid var(--line);
  font-size:15px;color:var(--steel)}
.notice::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--red)}
.notice-error::before{background:#C8452F}
.notice-ok::before{background:#7FB069}

.info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:22px}
.info-block{background:var(--panel);border:1px solid var(--line);padding:24px}
.info-block h3{font-family:"Orbitron",sans-serif;font-weight:800;font-size:12.5px;
  letter-spacing:.06em;text-transform:uppercase;color:#7C8794;margin:0 0 12px}
.info-block ul{list-style:none;margin:0;padding:0;display:grid;gap:8px}
.info-block a:hover{color:var(--halo)}

a.cline{display:block;font-family:"Orbitron",sans-serif;font-weight:600;
  font-size:17px;color:var(--white);padding:14px 0;
  border-bottom:1px solid var(--line-soft);position:relative;overflow:hidden}
a.cline:hover{color:var(--halo)}

.map-frame{border:1px solid var(--line);line-height:0;background:var(--panel)}
.map-frame iframe{width:100%;height:420px;border:0;filter:grayscale(1) invert(.92)
  contrast(.85)}


/* ==========================================================================
   11. HOURS TABLE
   ========================================================================== */
.hours{width:100%;border-collapse:collapse;background:var(--panel);
  border:1px solid var(--line)}
.hours th,.hours td{padding:12px 18px;text-align:left;
  border-top:1px solid var(--line-soft);font-size:15px}
.hours tr:first-child th,.hours tr:first-child td{border-top:0}
.hours th{font-family:"Orbitron",sans-serif;font-weight:700;font-size:13.5px;
  letter-spacing:.04em;text-transform:uppercase;color:var(--mute)}
.hours td{font-family:"Share Tech Mono",ui-monospace,monospace;font-size:13px;
  letter-spacing:.08em;color:var(--white);text-align:right}
.hours tr[data-today] th{color:var(--white)}
.hours tr[data-today] td{color:var(--red)}
.hours td.closed{color:#5E646C}


/* ==========================================================================
   12. THE MARK BUTTON
   The AES mark button is built around the AES oval at 2.045:1. The Cut
   Society logo is 2.76:1, so the button's aspect-ratio moves with it —
   otherwise the bezel would crop the artwork.
   ========================================================================== */
/* The button carries the CUT monogram, not the full wordmark, so its
   aspect ratio is the cropped one: 2.761 / 0.62 = 4.45. */
.aes-mark-btn{width:230px;aspect-ratio:4.45 / 1}
.aes-mark-btn .cs-mark{position:relative;z-index:2;width:100%;height:100%;
  filter:drop-shadow(0 0 20px rgba(184,188,194,.30))
         drop-shadow(0 3px 7px rgba(0,0,0,.62))}
.aes-mark-btn__bezel{inset:-13% -6%}
.aes-mark-btn__cap{color:var(--atom-ring)}

/* The AES rule keeps the title block clear of a 300px mark. Ours is 230px. */
.rhero .wrap > .spec,
.rhero .wrap > h1,
.rhero .wrap > .thesis,
.rhero .wrap > .pos{max-width:calc(100% - 280px)}
@media(max-width:760px){
  .rhero .wrap > .spec,
  .rhero .wrap > h1,
  .rhero .wrap > .thesis,
  .rhero .wrap > .pos{max-width:100%}
}


/* ==========================================================================
   13. FOOTER
   ========================================================================== */
footer.site .foot-grid{display:grid;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:26px;
  padding:44px 28px 10px;max-width:var(--maxw);margin:0 auto}
footer.site .foot-col h2{font-family:"Orbitron",sans-serif;font-weight:800;
  font-size:12.5px;letter-spacing:.06em;text-transform:uppercase;color:#7C8794;
  margin:0 0 12px}
footer.site .foot-col ul{list-style:none;margin:0;padding:0;display:grid;gap:8px}
footer.site .foot-col li{font-family:"Rajdhani",sans-serif;font-size:15px;
  letter-spacing:0;color:var(--mute)}
footer.site .foot-col a:hover{color:var(--white)}
footer.site .foot-brand{padding:0 28px;max-width:var(--maxw);margin:0 auto}


/* ==========================================================================
   14. SKIP LINK AND SCREEN-READER TEXT
   ========================================================================== */
.skip-link{position:absolute;left:-9999px;top:0;z-index:600;
  background:var(--panel);color:var(--white);padding:12px 20px;
  border:1px solid var(--red);font-family:"Orbitron",sans-serif;font-size:13px}
.skip-link:focus{left:12px;top:12px}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap}


/* ==========================================================================
   15. THE CHAMFER
   The brief's corner cut, applied where it reads as deliberate rather
   than decorative: the primary button and the section heads.
   ========================================================================== */
.btn.primary{
  clip-path:polygon(var(--chamfer) 0,100% 0,100% calc(100% - var(--chamfer)),
                    calc(100% - var(--chamfer)) 100%,0 100%,0 var(--chamfer));
  background:var(--red);border-color:var(--red);color:var(--ink);
}
.btn.primary:hover{background:var(--halo);border-color:var(--halo);
  color:var(--ink)}
.btn.invert{background:var(--white);border-color:var(--white);color:var(--ink)}
.btn.invert:hover{background:var(--halo);border-color:var(--halo)}

.section-head{display:grid;grid-template-columns:.9fr 1.1fr;gap:38px;
  align-items:end;margin-bottom:40px}
@media(max-width:820px){.section-head{grid-template-columns:1fr;gap:18px}}


/* ==========================================================================
   16. THE SPLASH — the opening reveal

   aes.css already builds this whole sequence. Everything below is an
   override of its palette, because the AES version is marble and warm
   backlight, and this one is black and chrome.

   The geometry, the timings, the specular sweep and the iris are all left
   exactly as they are on jjmccaffrey.com — they are driven by aes.js and
   aes-splash.js, and nothing here touches them.

   TO REMOVE THE SPLASH ENTIRELY: drop splash_block() from build_index()
   in the build script and rebuild. aes-splash.js only looks for
   #aesSplash, so it goes quiet by itself.
   ========================================================================== */

/* WHERE THE PLATE ACTUALLY LIVES
   ------------------------------
   aes.css puts the marble on #aesSplash itself. aes-atom.css then MOVES it,
   at line 480, with a higher-specificity rule:

       html #aesSplash{ background-image:none; background-color:transparent }
       html #aesSplash .s-plate{ background:url("marble.jpg") ... #10202F }

   because the iris mask has to be applied to a child rather than the root.
   So overriding #aesSplash does nothing — the marble is on .s-plate, behind
   an `html` prefix. These rules match that specificity and win on order,
   cut-society.css being loaded after aes-atom.css. Verified in the browser,
   not assumed: the first attempt targeted #aesSplash and had no effect. */

html #aesSplash .s-plate{
  background:radial-gradient(1200px 720px at 50% 44%,
    #14171B 0%, #0A0C0E 52%, #050505 100%) no-repeat #050505;
}

/* The vignette that rides on the plate. Cold and harder than the AES one,
   so the chrome edge of the mark stays the brightest thing on screen. */
html #aesSplash .s-plate::after{
  background:radial-gradient(56% 50% at 50% 46%,
    rgba(0,0,0,0) 0%, rgba(0,0,0,.66) 100%);
}

/* The mark sits above the plate, or the iris would open onto a hidden logo. */
#aesSplash .s-logo{z-index:2}
#aesSplash .strip,#aesSplash .tag{z-index:2}

/* The two light strips either side. --halo now carries the chrome
   specular, so they inherit the move without a value here. */

/* The breathing halo behind the mark. Chrome, so it reads as a lamp on
   metal rather than a warm backlight through a sign. */
#aesSplash .s-halo{
  background:radial-gradient(closest-side,
    rgba(228,232,237,0) 46%,
    rgba(228,232,237,.13) 62%,
    transparent 76%);
  filter:blur(14px);
}

/* The logo block. The supplied artwork is 2.76:1 rather than the AES
   sign's 2.05:1, so the width comes down to keep the same optical size. */
#aesSplash .s-logo{width:min(620px,72vw)}
#aesSplash .s-mark{
  position:relative;width:100%;height:auto;opacity:0;transform:scale(.9);
  transition:opacity .9s ease,transform 1.1s cubic-bezier(.2,.7,.2,1);
  filter:drop-shadow(0 14px 34px rgba(0,0,0,.75));
}
#aesSplash.lit .s-mark{opacity:1;transform:scale(1)}

/* aes.css targets `#aesSplash img` for the reveal, and there is no <img>
   here — the mark is inline SVG so it can carry the chrome gradient.
   The two rules above take its place. */

/* The specular pass. Rectangular, because the mark is a rectangle; the
   AES rule clips it to a circle for the oval logo. */
#aesSplash .s-shine{border-radius:0}
#aesSplash .s-shine::after{
  background:linear-gradient(105deg,transparent,rgba(255,255,255,.42),transparent)}

/* The strapline. Chrome-engraved rather than warm-stone-engraved, and
   sized against the shorter line. */
#aesSplash .tag{
  font-family:"Microgramma","Orbitron",sans-serif;font-weight:400;
  font-size:clamp(10px,1.9vw,26px);letter-spacing:.28em;color:#8D949C;
  text-shadow:
    0 1px 0 rgba(244,246,248,.55),
    0 2px 1px rgba(244,246,248,.20),
    0 -1px 1px rgba(0,0,0,.85),
    0 -2px 3px rgba(0,0,0,.6),
    0 3px 4px rgba(0,0,0,.4);
}

/* The splash sits above everything including the sticky header. */
#aesSplash{z-index:400}
body.splashing header.nav{z-index:1}


/* ==========================================================================
   17. THE SUB-PAGE HERO
   aes.css builds .rhero on the same marble.jpg as the splash. The salon is
   black and chrome, so the texture goes and a cold gradient takes its place.
   marble.jpg is still shipped because aes.css references it, and a 404 on
   every sub-page load is worse than 64KB sitting unused.
   ========================================================================== */
.rhero{
  background:
    linear-gradient(180deg, rgba(10,11,13,.2) 0%, rgba(5,5,5,.9) 100%),
    radial-gradient(900px 420px at 78% 30%, #16191D 0%, #0A0B0D 60%, #050505 100%)
    #050505;
}
.rhero::after{
  background:radial-gradient(closest-side, rgba(216,220,226,.07), transparent 70%);
}


/* ==========================================================================
   18. CORRECTIONS FOUND IN THE BROWSER

   Everything in this block is here because it was WRONG on screen, not
   because it was predicted. Each one names what it fixes.
   ========================================================================== */

/* --- the header was still navy -----------------------------------------
   aes.css sets header.nav's background as a literal rgba(10,22,34,.86)
   rather than through a variable, so re-pointing the palette in block 1
   could not reach it. Same construction, salon values. */
header.nav{
  background:rgba(6,7,9,.88);
  border-bottom:1px solid var(--line);
}
@supports (backdrop-filter:blur(14px)){
  header.nav{background:rgba(6,7,9,.72)}
}

/* --- the Atom Geometry button sat across the headline -------------------
   The AES rule pins it to the middle-right of .rhero, where a max-width
   on the title block keeps them apart. The index hero has no such guard
   and its headline runs the full width, so the mark landed on top of
   "Booked in under a minute."

   On the index hero it moves to the bottom-right corner, clear of both
   the headline and the centred address block. On sub-pages the AES
   position is correct and is left alone. */
.hero .aes-mark-btn{
  top:auto;bottom:7%;right:4%;
  width:180px;transform:none;
}
.hero .aes-mark-btn:hover{transform:scale(1.035)}
.hero .aes-mark-btn:active{transform:scale(.995)}
@media(max-width:1180px){.hero .aes-mark-btn{display:none}}

/* --- the player bar covered the address block --------------------------
   The player is fixed to the bottom of the window, so the last thing in
   the hero sits behind it on first load. aes.css already pads the footer
   for this; the hero needs the same. */
body.has-player .hero-in{padding-bottom:112px}
body.has-player .rbody{padding-bottom:120px}
@media(max-width:700px){
  body.has-player .hero-in{padding-bottom:96px}
}

/* --- the cut line overran the statement --------------------------------
   .statement::after spans the grid column, not the text, so on a line
   that wrapped short the rule carried on into empty space. Held back to
   the text measure instead. */
.statement{max-width:20ch}
@media(max-width:820px){.statement{max-width:none}}

/* --- the hero ran past the fold ----------------------------------------
   With the player bar docked, the address block landed behind it on a
   900px-tall window: padding-bottom cannot help, because the player is
   fixed to the VIEWPORT and the hero is taller than the viewport. The
   content has to come up instead. Mark and spacing tightened until the
   whole hero, address included, lands above the bar at 900px. */
.hero-mark{width:min(430px,58vw);margin:0 auto 20px}
.hero-in{padding:40px 28px 56px}
.hero .sub{margin-bottom:6px}
.hero-tags{margin:14px 0 24px}
.hero-meta{line-height:1.85}

/* --- the Atom Geometry button was below the fold -----------------------
   Bottom-right put it outside the first screen, so nobody would find the
   panel. It sits under the header instead, which is inside the hero and
   clear of the centred column at every width it is shown. */
.hero .aes-mark-btn{top:96px;bottom:auto;right:3.5%;width:168px}

/* The monogram is wider than it is tall, so the button shrinks and moves
   further from the headline than the full wordmark needed. */
.hero .aes-mark-btn{top:104px;width:150px}


/* ==========================================================================
   19. THE ATOM GEOMETRY BUTTON WAS UNCLICKABLE

   Found by driving the button in a browser rather than by reading the
   CSS, which is the only way this one shows up.

   aes.css gives .hero-in `position:relative; z-index:2` so the hero text
   sits above the background photograph. aes-atom.css gives .aes-mark-btn
   `position:absolute` and NO z-index at all — on jjmccaffrey.com it lives
   inside .rhero, where nothing else is raised, so it never needed one.

   Moving it into .hero put it underneath .hero-in. It still rendered,
   still lit on hover in the corner where nothing overlapped, and looked
   completely normal — but .hero-in swallowed every click across most of
   its area, so the Atom Geometry panel could not be opened from the home
   page at all.

   Raised above .hero-in (2) and kept below the sticky header (300), so
   the header still takes its own clicks where the two are close.
   ========================================================================== */
.hero .aes-mark-btn{z-index:6}

/* The same guard on the sub-page hero. .rhero raises nothing today, so
   this changes nothing now — it stops the identical fault reappearing if
   a stacking context is ever added there. */
.rhero .aes-mark-btn{z-index:6}

/* The bezel and caption are children of the button, so they inherit its
   new stacking context. Nothing else needs raising. */


/* ==========================================================================
   20. THE ATOM GEOMETRY PANEL WAS STILL AES NAVY

   Two separate faults, both found by opening the panel and looking at it
   rather than by reading the code.

   (a) THE BUTTON ORBITAL WAS BLUE.
       assets/atom-config.json still carried the AES Cherenkov palette -
       col_ring #9DC6FF, col_glow #3E7BF5. Only splash-config.json had been
       recoloured, so the splash imploded in chrome and then every button on
       the site hovered in blue. Fixed in the JSON, not here.

   (b) THE PANEL SHELL IS HARDCODED.
       aes-atom.css defines --atom-glow and --atom-ring as variables, which
       block 1 of this file already re-points. But roughly a dozen values in
       that stylesheet are literal rgba(62,123,245,...) and #9DC6FF rather
       than var() references, so they could not follow. Those are overridden
       below, matched selector for selector.

   Nothing in aes-atom.css is edited. If it is ever replaced with a newer
   copy from jjmccaffrey.com, this block still applies.
   ========================================================================== */

/* --- panel shell --- */
.aes-ap{
  background:rgba(8,9,11,.95);
  border:1px solid rgba(184,188,194,.20);
  color:var(--steel);
}

/* --- the plain-English note --- */
.aes-ap__note{
  border:1px solid rgba(184,188,194,.30);
  border-left:3px solid var(--red);
  border-radius:0;
  background:rgba(184,188,194,.05);
}
.aes-ap__note h3{color:var(--atom-ring)}
.aes-ap__note p{color:var(--steel)}
.aes-ap__note b{color:var(--white)}
.aes-ap__note .aes-ap__warn{color:#C9A87C}

/* --- card headings and unit labels --- */
.aes-ap__card h3,
.aes-ap__cardnote,
.aes-ap__num,
.aes-ap__unit{color:var(--atom-ring)}

/* --- focus rings and active states ---
   The blue 2px ring is the panel's focus indicator, so it has to stay
   visible: chrome at the same alpha, not removed. */
.aes-ap input:focus,
.aes-ap select:focus,
.aes-ap textarea:focus,
.aes-ap button:focus-visible{
  border-color:var(--atom-ring);
  box-shadow:0 0 0 2px rgba(216,220,226,.22);
}
.aes-ap__foot button:hover,
.aes-ap__bar button:hover{
  border-color:var(--atom-ring);
  color:var(--white);
  background:rgba(184,188,194,.10);
}

/* --- sliders --- */
.aes-ap input[type=range]{accent-color:var(--red)}

/* --- the mark button bezel hover glow --- */
.aes-mark-btn:hover .aes-mark-btn__bezel{
  box-shadow:
    inset 0 4px 9px rgba(0,0,0,.92),
    inset 0 -3px 3px rgba(0,0,0,.34),
    inset 0 -1px 0 rgba(222,236,252,.52),
    inset 0 0 0 1px rgba(216,220,226,.30),
    inset 0 0 26px rgba(216,220,226,.13),
    0 14px 30px rgba(0,0,0,.46),
    0 0 34px rgba(216,220,226,.26);
}

/* Panel corners follow the site: nothing is rounded. */
.aes-ap,.aes-ap input,.aes-ap select,.aes-ap textarea,
.aes-ap button,.aes-ap__card,.aes-ap__demo{border-radius:0}


/* ==========================================================================
   21. STAFF SIGN-IN LINK

   The admin area existed with no way to reach it — the only route was
   typing the URL. It now appears in the footer, twice: in the Bookings
   column where the salon would look for it, and in the bottom bar so it
   is reachable from the foot of any page.

   Deliberately understated rather than hidden. Obscurity is not what
   protects this page — bcrypt, throttling, CSRF and the session rules
   are. A link a member of staff cannot find is a support call, not a
   security control.

   rel="nofollow" on the markup, Disallow in robots.txt and noindex on
   the page itself mean linking it cannot put it in a search result.
   ========================================================================== */
.foot-staff{
  position:relative;
  color:#6E7883;
  transition:color .2s;
}
.foot-staff::before{
  content:"";display:inline-block;width:6px;height:6px;margin-right:8px;
  background:var(--red);opacity:.55;transform:rotate(45deg);
  transition:opacity .2s;
}
.foot-staff:hover,
.foot-staff:focus-visible{color:var(--white)}
.foot-staff:hover::before,
.foot-staff:focus-visible::before{opacity:1}


/* ==========================================================================
   22. CHROME AND ENGRAVED TEXT

   Two finishes, both pure CSS, both degrading to plain legible text where
   they are not supported.

   .chrome    polished metal. A background gradient clipped to the glyphs,
              with a dark drop shadow underneath so it does not dissolve
              into a dark background.

   .engraved  cut INTO the surface. The trick is two shadows in opposition:
              a dark one above and a light one below. That is the opposite
              of a raised letter, and the brain reads the difference as
              depth rather than as two shadows.

   WHY NOT -webkit-text-stroke or a filter
   ---------------------------------------
   Both wreck subpixel rendering on small text and make body copy look
   furry. These are display finishes: use them on headings, never on a
   paragraph.

   ACCESSIBILITY
   -------------
   background-clip:text needs a transparent fill, and a transparent fill
   with no background is invisible text. The @supports guard below means
   the colour is only given away where the clip actually works.
   ========================================================================== */

/* --- polished chrome --------------------------------------------------- */
.chrome{
  color:var(--white);                       /* the fallback, always set */
  position:relative;
  text-shadow:0 2px 10px rgba(0,0,0,.55);
}
@supports ((background-clip:text) or (-webkit-background-clip:text)){
  .chrome{
    background:linear-gradient(178deg,
      #6E757E 0%, #FFFFFF 14%, #C6CBD2 30%,
      #4E545C 48%, #9AA1AA 56%,
      #FFFFFF 72%, #B4BAC2 86%, #6E757E 100%);
    -webkit-background-clip:text;
    background-clip:text;
    color:transparent;
    -webkit-text-fill-color:transparent;
    text-shadow:none;
    /* The gradient replaces the shadow, so the depth has to come back as
       a filter or the letters float. */
    filter:drop-shadow(0 1px 0 rgba(255,255,255,.16))
           drop-shadow(0 3px 8px rgba(0,0,0,.6));
  }
}

/* --- engraved ---------------------------------------------------------- */
.engraved{
  color:#8F969F;
  text-shadow:
    0 -1px 1px rgba(0,0,0,.92),
    0 -2px 3px rgba(0,0,0,.55),
    0  1px 0  rgba(226,232,240,.34),
    0  2px 3px rgba(226,232,240,.13);
}

/* Engraved on a light panel needs the opposite weighting, or it reads as
   embossed. */
.panel-light .engraved,
.engraved.on-light{
  color:#5A6068;
  text-shadow:
    0 -1px 1px rgba(0,0,0,.28),
    0  1px 0  rgba(255,255,255,.85);
}

/* --- chrome that catches the light as it scrolls ------------------------
   The sweep is a second, wider gradient drifting across the same clip.
   Purely decorative, so it stops entirely under reduced motion. */
@supports ((background-clip:text) or (-webkit-background-clip:text)){
  .chrome-live{
    background:linear-gradient(100deg,
      #6E757E 0%, #C6CBD2 18%, #FFFFFF 26%, #9AA1AA 38%,
      #4E545C 50%, #9AA1AA 62%, #FFFFFF 74%, #C6CBD2 82%, #6E757E 100%);
    background-size:280% 100%;
    -webkit-background-clip:text;
    background-clip:text;
    color:transparent;
    -webkit-text-fill-color:transparent;
    animation:chromeSweep 9s linear infinite;
    filter:drop-shadow(0 2px 7px rgba(0,0,0,.6));
  }
}
@keyframes chromeSweep{
  0%   {background-position:  0% 50%}
  100% {background-position:280% 50%}
}
@media(prefers-reduced-motion:reduce){
  .chrome-live{animation:none;background-position:40% 50%}
}

/* --- applied to the site's own headings --------------------------------- */
h1, .statement, .price-group-title, .band-head h2{
  /* inherits whichever finish the markup asks for; nothing forced here */
}

/* The hero headline carries the live sweep — it is the one place on the
   site where a moving highlight is the point rather than a distraction. */
.hero h1 span{
  background:linear-gradient(178deg,
    #7A818A 0%, #FFFFFF 16%, #C6CBD2 32%,
    #565C64 50%, #A6ADB6 60%, #FFFFFF 76%, #7A818A 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
  filter:drop-shadow(0 3px 10px rgba(0,0,0,.65));
}
@supports not ((background-clip:text) or (-webkit-background-clip:text)){
  .hero h1 span{color:var(--white);-webkit-text-fill-color:var(--white)}
}

/* Section headings get the engraved cut: they sit ON the surface rather
   than floating above it, which suits a heading that introduces a band. */
.band-head h2,
.rhero h1{
  color:#D8DDE4;
  text-shadow:
    0 -1px 1px rgba(0,0,0,.9),
    0 -2px 4px rgba(0,0,0,.5),
    0  1px 0  rgba(226,232,240,.28),
    0  2px 4px rgba(226,232,240,.10);
}

/* --- account page bookings --- */
.acct-booking{display:flex;flex-wrap:wrap;gap:16px;justify-content:space-between;
  align-items:center;background:var(--panel);border:1px solid var(--line);
  border-top:0;padding:18px 22px}
.acct-booking:first-of-type{border-top:1px solid var(--line)}
.acct-booking b{display:block;color:var(--white);font-family:"Orbitron",sans-serif;
  font-weight:700;font-size:16px}
.acct-booking .muted{display:block;margin-top:5px;font-family:"Share Tech Mono",monospace;
  font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:#6E7883}
.acct-booking.is-past{opacity:.6}
.acct-actions{display:flex;align-items:center;gap:12px}
.acct-actions form{margin:0}
