/* ---------------------------------------------------------------------------
   Harry Grooms - the interface layer that sits on top of both halves.

   Its own file rather than an addition to either of the other two, for one
   reason: admin.css is scoped under .ad and site.css is not, and the things in
   here - the theme, the consent banner, the confirm dialog, the toasts - belong
   to the page, not to either app. Adding them to admin.css would mean writing
   unscoped rules into the file whose whole discipline is that it has none.

   THE RULE THIS FILE EXISTS TO ENFORCE:

     A theme is only as deep as its tokens. Swapping custom properties reaches
     colours that were *written* as custom properties, and nothing else.

   So never write a literal colour in site.css or admin.css. Every value below was
   measured before it was chosen - the ratios are in the comments - and
   tools/darktest.js re-measures every one of them on every route, both themes,
   two viewports, and exits with the failure count.
--------------------------------------------------------------------------- */

/* ---------- dark theme ----------
   Three states, and the order matters. Bare :root in site.css is the light
   palette. The media query catches a visitor whose system is dark and who has
   never touched the toggle. The explicit attribute wins over both, in BOTH
   directions, so choosing light on a dark laptop actually gives light.

   The two blocks below - [data-theme="dark"] and the media query - must stay
   identical. A token added to one and not the other is invisible until somebody
   with a dark laptop opens the site. audittest.js diffs them. */

:root[data-theme="dark"]{
  /* ---- ground ----
     Three levels, not one. #0e0e0f is the page, #16161a a raised card, #1f1f24 a
     card on a card (a drawer over a panel, an input inside a panel). Very
     slightly cool: a barbershop at night is steel, mirror and tile, and the brass
     accent needs a cool ground to read as brass rather than as mud. */
  --paper:#0e0e0f; --bone:#16161a; --bone-2:#1f1f24;

  /* ---- text ----
     --ink-3 and --ink-4 are LIFTED well above a naive mirror of their light
     values. Mirroring #5e5954 lands at 2.8:1 on this ground and takes every
     caption, price, table header and slot label with it. Measured here:
     ink 17.26, ink-2 13.06, ink-3 8.37, ink-4 5.94 on --paper; the worst case
     (ink-4 on --bone-2) is 5.05. */
  --ink:#f4f2ee; --ink-2:#d8d4cd; --ink-3:#b0aaa1; --ink-4:#948e85;

  /* ---- accent ----
     The brass is brightened. #7d5a1c on near-black is 1.6:1 - invisible. #d9ad61
     measures 9.28 on --paper and 7.89 on --bone-2, so it can carry link text and
     the small caps it is actually used on, not only a 1px border. */
  --brass:#d9ad61; --brass-lt:#e0bb7a; --brass-pale:#2a2418;
  /* the pole. Oxblood, and the one colour in the system allowed to be loud. */
  --ox:#e08a8a; --ox-pale:#2c1b1b;

  --mist:#3a3a41; --line:#2b2b31;
  --ok:#6fc194; --ok-bg:#16271d;
  --warn:#e0b25c; --warn-bg:#2b2315;
  --bad:#ea8686; --bad-bg:#2c1a1a;
  --info:#8ab8e4; --info-bg:#152230;

  /* ---- a small filled control ----
     Stays a TRUE inversion: pale fill, dark text. A primary button or a selected
     time slot rendered as dark-grey-on-dark-grey reads as disabled, and the whole
     point of the fill is that it does not. */
  --invert-bg:#f4f2ee; --invert-fg:#131316;

  /* ---- a large inverted surface ----
     Does NOT invert. A white footer across the bottom of a dark page is a torch
     in the face, so the footer, the announcement strip and the console sidebar
     become a lifted panel that is still distinct from the page behind them. */
  --panel-bg:#141418; --panel-fg:#f4f2ee; --panel-fg-rgb:244,242,238; --panel-mute:#b6b0a7;

  --on-accent:#14120e;   /* text sitting on a brass fill: 9.00 against #d9ad61 */

  /* ---- washes ----
     Channels, not hex, because they are used at a dozen alpha values. --scrim is
     the gradient that keeps the hero headline legible over the photography;
     --glass is the frosted bar the header becomes once it leaves the hero. */
  --scrim-rgb:14,14,15;
  --glass-rgb:16,16,19;
  /* The chair gallery. Light, it is a white studio; dark, a black box. This is
     the one surface where a straight inversion is right rather than a lifted
     panel - the plates are lit either way. motion.js reads the SAME property for
     the canvas ground, so change it here or the two drift. */
  --room-bg:#131316; --room-rgb:19,19,22;

  color-scheme: dark;
}

/* The console keeps its own ground so a sidebar can sit against the page without
   either becoming the other. Same ladder, shifted one step. */
:root[data-theme="dark"] .ad{
  --paper:#16161a; --bone:#0e0e0f; --surface:#16161a; --bone-2:#1f1f24;
  --ink:#f4f2ee; --ink-2:#d8d4cd; --ink-3:#b0aaa1; --ink-4:#948e85;
  --brass:#d9ad61; --brass-lt:#e0bb7a; --brass-pale:#2a2418;
  --ox:#e08a8a; --ox-pale:#2c1b1b;
  --mist:#3a3a41; --line:#2b2b31;
  --ok:#6fc194; --ok-bg:#16271d; --warn:#e0b25c; --warn-bg:#2b2315;
  --bad:#ea8686; --bad-bg:#2c1a1a; --info:#8ab8e4; --info-bg:#152230;
  --invert-bg:#f4f2ee; --invert-fg:#131316;
  --panel-bg:#09090b; --panel-fg:#f4f2ee; --panel-fg-rgb:244,242,238; --panel-mute:#a8a29a;
  --on-accent:#14120e;
}

/* Photography is shot bright. Left untouched on a dark page every card becomes a
   lightbox, so the whole grid is taken down a little - not inverted, which would
   turn a black fade grey, just dimmed and slightly de-saturated. The hero is
   exempt: it is already dark and dimming it twice buries the face. */
:root[data-theme="dark"] img:not([data-nodim]){ filter: brightness(.9) saturate(.96); }
:root[data-theme="dark"] .hero img,
:root[data-theme="dark"] .pole,
:root[data-theme="dark"] .cat img{ filter:none }

@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --paper:#0e0e0f; --bone:#16161a; --bone-2:#1f1f24;
    --ink:#f4f2ee; --ink-2:#d8d4cd; --ink-3:#b0aaa1; --ink-4:#948e85;
    --brass:#d9ad61; --brass-lt:#e0bb7a; --brass-pale:#2a2418;
    --ox:#e08a8a; --ox-pale:#2c1b1b;
    --mist:#3a3a41; --line:#2b2b31;
    --ok:#6fc194; --ok-bg:#16271d;
    --warn:#e0b25c; --warn-bg:#2b2315;
    --bad:#ea8686; --bad-bg:#2c1a1a;
    --info:#8ab8e4; --info-bg:#152230;
    --invert-bg:#f4f2ee; --invert-fg:#131316;
    --panel-bg:#141418; --panel-fg:#f4f2ee; --panel-fg-rgb:244,242,238; --panel-mute:#b6b0a7;
    --on-accent:#14120e;
    --scrim-rgb:14,14,15;
    --glass-rgb:16,16,19;
    --room-bg:#131316; --room-rgb:19,19,22;
    color-scheme: dark;
  }
  :root:not([data-theme="light"]) .ad{
    --paper:#16161a; --bone:#0e0e0f; --surface:#16161a; --bone-2:#1f1f24;
    --ink:#f4f2ee; --ink-2:#d8d4cd; --ink-3:#b0aaa1; --ink-4:#948e85;
    --brass:#d9ad61; --brass-lt:#e0bb7a; --brass-pale:#2a2418;
    --ox:#e08a8a; --ox-pale:#2c1b1b;
    --mist:#3a3a41; --line:#2b2b31;
    --ok:#6fc194; --ok-bg:#16271d; --warn:#e0b25c; --warn-bg:#2b2315;
    --bad:#ea8686; --bad-bg:#2c1a1a; --info:#8ab8e4; --info-bg:#152230;
    --invert-bg:#f4f2ee; --invert-fg:#131316;
    --panel-bg:#09090b; --panel-fg:#f4f2ee; --panel-fg-rgb:244,242,238; --panel-mute:#a8a29a;
    --on-accent:#14120e;
  }
  :root:not([data-theme="light"]) img:not([data-nodim]){ filter: brightness(.9) saturate(.96); }
  :root:not([data-theme="light"]) .hero img,
  :root:not([data-theme="light"]) .pole,
  :root:not([data-theme="light"]) .cat img{ filter:none }
}

/* ---------- the theme toggle ---------- */
.themebtn{display:inline-flex;align-items:center;justify-content:center;
  width:40px;height:40px;border:0;background:none;color:inherit;cursor:pointer;
  border-radius:50%;transition:background .2s}
.themebtn:hover{background:rgba(var(--panel-fg-rgb),.10)}
.themebtn svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .45s cubic-bezier(.16,1,.3,1)}
.themebtn[aria-pressed="true"] svg{transform:rotate(-25deg)}
.themebtn .sun,.themebtn .moon{transition:opacity .3s}
.themebtn[aria-pressed="true"] .sun{opacity:0}
.themebtn[aria-pressed="false"] .moon{opacity:0}
.themebtn .moon,.themebtn .sun{transform-origin:12px 12px}
/* 40px is comfortable for a mouse and two pixels short of what a thumb wants, so
   it grows only where the target is a finger. Measured at 390px by the audit. */
@media(max-width:900px){.themebtn{width:44px;height:44px}}

/* ---------- skip to content ----------
   Not display:none. It has to be focusable, and it has to be REACHED - a link
   that is off-screen at -60px and never comes back is worse than no link. */
.skip{position:fixed;top:-60px;left:16px;z-index:400;
  background:var(--invert-bg);color:var(--invert-fg);
  padding:12px 22px;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:600;transition:top .2s}
.skip:focus{top:12px}

/* ---------- back to top ---------- */
.totop{position:fixed;right:22px;bottom:96px;z-index:180;
  width:46px;height:46px;border:1px solid var(--line);border-radius:50%;
  background:var(--paper);color:var(--ink);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  opacity:0;pointer-events:none;transform:translateY(10px);
  transition:opacity .3s,transform .3s;box-shadow:0 6px 24px rgba(0,0,0,.13)}
.totop.on{opacity:1;pointer-events:auto;transform:none}
.totop svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
@media(max-width:700px){.totop{right:14px;bottom:84px;width:44px;height:44px}}

/* ---------- consent ----------
   Its background follows --panel-bg, NOT --ink. --ink inverts with the theme, so
   a bar written against it was light-grey text on a near-white slab in dark mode:
   the right height, two 44px buttons, the choice stored correctly, and unreadable.
   That bug is the reason --panel-* exists as a separate pair. */
.cc{position:fixed;left:0;right:0;bottom:0;z-index:320;
  background:var(--panel-bg);color:var(--panel-fg);
  padding:18px clamp(16px,4vw,40px);
  display:none;gap:20px;align-items:center;justify-content:space-between;flex-wrap:wrap;
  box-shadow:0 -10px 40px rgba(0,0,0,.28)}
.cc.on{display:flex}
.cc p{margin:0;font-size:13px;max-width:70ch;color:var(--panel-mute);line-height:1.55}
.cc p b{color:var(--panel-fg)}
.cc-act{display:flex;gap:10px;flex-wrap:wrap}
.cc button{min-height:44px;padding:11px 22px;font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;font-weight:600;cursor:pointer;border:1px solid var(--panel-fg);
  background:var(--panel-fg);color:var(--panel-bg);transition:.2s}
.cc button.ghost{background:transparent;color:var(--panel-fg)}
.cc button.ghost:hover{background:rgba(var(--panel-fg-rgb),.14)}
.cc button:hover{background:var(--brass);border-color:var(--brass);color:var(--on-accent)}
@media(max-width:640px){.cc{flex-direction:column;align-items:stretch}
  .cc-act{justify-content:stretch}.cc-act button{flex:1}}

/* ---------- toasts ---------- */
.toasts{position:fixed;left:50%;transform:translateX(-50%);bottom:26px;z-index:400;
  display:flex;flex-direction:column;gap:10px;align-items:center;pointer-events:none;
  width:min(440px,calc(100vw - 32px))}
.toast{pointer-events:auto;width:100%;
  background:var(--invert-bg);color:var(--invert-fg);
  padding:14px 18px;display:flex;gap:12px;align-items:flex-start;
  font-size:13.5px;line-height:1.45;
  box-shadow:0 12px 40px rgba(0,0,0,.3);
  animation:toastIn .34s cubic-bezier(.16,1,.3,1)}
.toast.out{animation:toastOut .26s ease forwards}
.toast svg{width:17px;height:17px;flex:none;margin-top:1px;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.toast.ok svg{stroke:var(--ok)}
.toast.bad svg{stroke:var(--bad)}
.toast.warn svg{stroke:var(--warn)}
.toast .x{margin-left:auto;background:none;border:0;color:inherit;cursor:pointer;
  opacity:.6;font-size:17px;line-height:1;padding:0 2px}
.toast .x:hover{opacity:1}
@keyframes toastIn{from{opacity:0;transform:translateY(14px) scale(.97)}to{opacity:1;transform:none}}
@keyframes toastOut{to{opacity:0;transform:translateY(8px) scale(.98)}}

/* ---------- confirm dialog ----------
   A real dialog, because window.confirm() cannot be styled, cannot be themed, and
   on a phone reads as a browser warning rather than as the shop asking. */
.dlg-scrim{position:fixed;inset:0;z-index:420;background:rgba(0,0,0,.55);
  display:none;align-items:center;justify-content:center;padding:20px;
  backdrop-filter:blur(3px)}
.dlg-scrim.on{display:flex}
.dlg{background:var(--paper);color:var(--ink);width:min(440px,100%);
  padding:32px;box-shadow:0 30px 90px rgba(0,0,0,.4);
  animation:dlgIn .3s cubic-bezier(.16,1,.3,1)}
@keyframes dlgIn{from{opacity:0;transform:translateY(16px) scale(.98)}to{opacity:1;transform:none}}
.dlg h3{font-size:19px;margin:0 0 10px}
.dlg p{font-size:14px;color:var(--ink-2);margin:0 0 22px;line-height:1.6}
.dlg-act{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}
.dlg-act button{min-height:44px;padding:12px 24px;font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;font-weight:600;cursor:pointer;
  border:1px solid var(--invert-bg);background:var(--invert-bg);color:var(--invert-fg);transition:.2s}
.dlg-act button.ghost{background:transparent;color:var(--ink)}
.dlg-act button.ghost:hover{background:var(--bone-2)}
.dlg-act button.danger{background:var(--bad);border-color:var(--bad);color:var(--invert-fg)}
.dlg-act button:not(.ghost):not(.danger):hover{background:var(--brass);border-color:var(--brass);color:var(--on-accent)}

/* ---------- form result states ---------- */
.fr{margin-top:14px;padding:13px 16px;font-size:13px;line-height:1.5;display:flex;gap:10px;align-items:flex-start}
.fr.ok{background:var(--ok-bg,var(--bone));color:var(--ok);border-left:3px solid var(--ok)}
.fr.bad{background:var(--bad-bg,var(--bone));color:var(--bad);border-left:3px solid var(--bad)}
.fr svg{width:16px;height:16px;flex:none;margin-top:2px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}
.field-err{display:block;color:var(--bad);font-size:12px;margin-top:5px;line-height:1.4}
.field input[aria-invalid="true"],.field select[aria-invalid="true"],.field textarea[aria-invalid="true"]{
  border-color:var(--bad)}

/* ---------- password field ---------- */
.pw-wrap{position:relative}
.pw-wrap input{padding-right:46px}
.pw-eye{position:absolute;right:4px;top:50%;transform:translateY(-50%);
  width:38px;height:38px;border:0;background:none;color:var(--ink-3);cursor:pointer;
  display:flex;align-items:center;justify-content:center}
.pw-eye:hover{color:var(--ink)}
.pw-eye svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.pw-meter{margin-top:9px}
.pw-bars{display:flex;gap:4px}
.pw-bars i{height:3px;flex:1;background:var(--mist);transition:background .3s}
.pw-meter[data-score="0"] i:nth-child(-n+1),
.pw-meter[data-score="1"] i:nth-child(-n+1){background:var(--bad)}
.pw-meter[data-score="2"] i:nth-child(-n+2){background:var(--warn)}
.pw-meter[data-score="3"] i:nth-child(-n+3){background:var(--ok)}
.pw-meter[data-score="4"] i{background:var(--ok)}
.pw-note{font-size:12px;color:var(--ink-3);margin-top:6px;line-height:1.45}

/* ---------- accordion ---------- */
.acc-item{border-bottom:1px solid var(--line)}
.acc-q{width:100%;text-align:left;background:none;border:0;cursor:pointer;
  padding:20px 40px 20px 0;font-size:15px;font-weight:500;color:var(--ink);
  position:relative;display:block;min-height:44px}
.acc-q::after{content:'';position:absolute;right:8px;top:50%;width:11px;height:11px;
  border-right:1.6px solid var(--ink-3);border-bottom:1.6px solid var(--ink-3);
  transform:translateY(-70%) rotate(45deg);transition:transform .3s}
.acc-item.on .acc-q::after{transform:translateY(-30%) rotate(225deg)}
.acc-a{overflow:hidden;height:0;transition:height .35s cubic-bezier(.16,1,.3,1)}
.acc-a>div{padding:0 0 22px;color:var(--ink-2);font-size:14px;line-height:1.7;max-width:72ch}

/* ---------- copy button ---------- */
.copy{display:inline-flex;align-items:center;gap:7px;background:none;border:1px solid var(--line);
  color:var(--ink-2);padding:7px 12px;font-size:11.5px;cursor:pointer;transition:.2s;min-height:34px}
.copy:hover{border-color:var(--ink-3);color:var(--ink)}
.copy svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.copy.done{border-color:var(--ok);color:var(--ok)}

/* ---------- skeletons ---------- */
.sk{background:linear-gradient(90deg,var(--bone-2) 25%,var(--bone) 37%,var(--bone-2) 63%);
  background-size:400% 100%;animation:skWave 1.3s ease-in-out infinite}
@keyframes skWave{0%{background-position:100% 50%}100%{background-position:0 50%}}
@media(prefers-reduced-motion:reduce){.sk{animation:none}}

/* ---------- print ----------
   A booking confirmation and a day sheet are the two things anyone prints here.
   Everything else comes off the page. */
@media print{
  .hdr,.ftr,.announce,.cc,.totop,.toasts,.wa,.side,.mnav,.skip,.themebtn,
  .drawer,.scrim,.no-print{display:none !important}
  body{background:#fff !important;color:#000 !important}
  main,.main{padding:0 !important}
  a[href^="#"]::after{content:''}
  .print-only{display:block !important}
  .card,.panel,.slotgrid{break-inside:avoid}
}
.print-only{display:none}
